Distributed Application Programming in C++ with Cdrom
Authors: Randall A. Maddox
Venue:  (2000)

From the Book:PREFACE: IntroductionTarget AudienceThis is not a book for beginners, nor the faint of heart.In writing this book, I am making the following assumptions about the reader. You are an experienced C++ developer with at least two years experience on medium- to large-scale projects in a Unix environment. You understand what a shared object library is and why it might be useful. You understand the difference between, and are aware of at least some of the issues involved in, multiprocessing and multithreading. You are at least aware of the standard Unix interprocess communication (IPC) mechanisms such as sockets and shared memory. You understand at least some of the concepts behind why an application needs to be distributed in order to be scalable, and you have probably worked on at least one distributed application. You are familiar with the work of at least some of the authors listed in the bibliography, and you may very well have some of these same texts in your own personal reference library. You are dedicated to learning more about the craft of software development in order to improve your skills so that you can compete with the very best world-class developers. In other words, you are most likely either a serious professional developer who is interested in learning more about the practical application of advanced C++ and Unix features and concepts in the real world, or, a student in a graduate level class on distributed architecture or advanced Unix programming in C++.What This Book Is AboutThis book is about architectingandimplementing high-quality infrastructure code in C++.Almost any piece of software, if viewed at a certain level of abstraction, can be conceptually divided into two layers that reflect the natural division of work performed by most programs. One layer is the visible portion of the software that interacts with the external world. To many, this visible layer is the software, but behind that layer, rarely visible to the outside world, is an underlying infrastructure that supports the visible portion of the software.This fundamental division is the yin and yang of software. The dark and the light. The two sides of a single coin. Neither can exist without the other. Only together do these two halves make a whole. There is no great application that is not supported by a great infrastructure, and as the software we develop becomes ever larger and more complex, maintaining a clean division of labor between application and infrastructure becomes ever more critical.The infrastructure is the beams and plumbing and wiring hidden inside the walls. It is not the house, but the house is as useless without it as it is without the house.Another way to look at this is through the lens of what is generally accepted as a standard layered model of an application architecture consisting of a presentation layer, a rules and interactions layer, and a support layer. The presentation layer handles the user interface and controls interactions between the user and the software. The rules and interactions layer embodies the logical operations and consistency constraints of the application and controls the software's responses to the user's interactions. Together, these layers comprise the outer, visible portion of the software.Underneath these layers, invisible to most users, is the infrastructure support layer that both insulates the outer layers from, and provides them access to, the underlying machine upon which the software runs and the services and capabilities it provides.This fundamental division between application and infrastructure within programs is reflected in the developers who design and write software. Most software development groups can be conceptually divided along similar lines, with a User Interface or Application team working on the visible portion of the software, supported by an Architecture or Library team who provide the underlying infrastructure code. The names of these groups vary widely, and the division of labor among developers may be obscured, but developers do naturally gravitate toward the layer that most appeals to them.The major difference between these two groups is in what knowledge is most useful and what level of abstraction is most appropriate. The outer layers tend to require more product- and domain-specific knowledge and to be more abstract. These layers are designed and written in terms of application-level abstractions, which should be more or less recognizable to a user of the system. These layers are closer to the problem domain.The underlying layers, by contrast, tend to require more platform- and language-specific knowledge and to be less abstract. These layers are designed and written in terms of system-level abstractions, which need to be available in a generic way to the application layers. These layers are closer to the solution domain.Thus, application developers tend to design and write more abstract code that is visible to the outside world, while infrastructure developers tend to design and write less abstract code that is used by application developers. Application developers tend to get most of the glory, while infrastructure developers help to make that possible. Application developers also get most of the heartache of dealing with external clients and their amorphous and ever-changing requirements. Infrastructure developers, writing for an audience with a better understanding of what it is possible to ask for, are often spared at least some of this misery.This book is written for, and from the viewpoint of, the experienced infrastructure developer. This is not to downplay the importance of the application side of development, nor of introductory C++ texts. It is simply that there are already a number of excellent books out there for application developers, and for those who are new to C++, while there are not yet as many good books for experienced infrastructure developers. This book aims to address that disparity.If you are an experienced infrastructure developer who wants to learn more about using C++, or who wants a better understanding of the infrastructure of C++ itself, then this book is for you.Becoming One With C++C++ is a large, complex, powerful, and extremely expressive language. Its size and complexity mean that the learning curve for C++ is both long and steep, while its power and expressiveness mean that the reward for getting over that hump is correspondingly great. It takes years of study to become a good C++ developer, but the more you learn the better you can express yourself and the better you can make use of the powerful features of C++ in your code.What I mean by "becoming one with C++" is more than just understanding and assimilating the language itself. C++ was not invented in a vacuum. Dr. Stroustrup invented C++ to meet the needs of real programmers working on real projects. You should read his book The Design and Evolution of C++ for more insight into how C++ came to be and why it contains the features it does. But the key point here is that C++ was designed, and evolved, according to a plan. Because of this, we can reasonably expect C++ to make sense according to its own internal logic.When I talk about becoming one with C++, what I mean is first having a thorough understanding of the language itself, and second, developing an equally thorough understanding of the internal logic behind the design of the language and what that internal logic implies about how we can best make use of C++.An understanding of the features of C++ allows us to use the language, but an understanding of the internal logic of C++ allows us to think in C++. Being able to think in C++ helps us to program in ways the language supports naturally, rather than fighting against the language by trying to use it in ways it was never intended to support.Think of it as learning a foreign language. First you learn a few words and simple phrases. Then you start memorizing more words and learning grammar and syntax rules. Once you get enough of that down, then you can make rudimentary use of the new language. For example, a few weeks of instruction and a phrase book will probably get you through a short vacation in France.That much knowledge will absolutely not, however, allow you to write a French novel. In order to reach that level of expertise, you would naturally expect to spend years studying the French language and culture in order to develop enough of a context to be able to write a novel. That is, you would need to assimilate the French language and culture so that you could think in French and express those thoughts as a native French speaker would. Only by internalizing the French language and culture to the point that it was a part of you could you expect to write a French novel.In other words, if you want to write a French novel, then you first need to become one with the French language and culture. Please do note the subtle, but very significant, difference between "a novel in French" and "a French novel". The first is merely a novel that is written down using the French language, while the second is a novel that both reflects and is a part of the French culture.Similarly, a few weeks of C++ instruction and a manual will allow us to compile and run the traditional "Hello, world!" and other toy programs, but this in no way prepares us for writing real programsa sad fact that, unfortunately, all too many software developers and managers alike fail to grasp.A guaranteed recipe for failure is to take a group of C developers, no matter how competent, send them to a six-week class on C++, and then expect them to develop the company's next wonder product in C++.But, I already hear the objections, C++ is just the next step up from C, and besides, a software product is nowhere near as complicated as a novel.Sorry. Totally wrong on both counts.First, C++ is as different from C as night is from day. In fact, C++ is in many ways more similar to Pascal or Modula-2 than it is to C. The strong type-checking and fine grain scope control of those languages are mirrored in C++. And Modula-2 has the concept of a module body that is guaranteed to execute before any function in a module, rather like a constructor in C++. So do not make the mistake of thinking that a C background necessarily makes for a better C++ developer. C++ is a whole different way of thinking. It is a different box of tools that need to be used in different ways.Second, a novel is significantly less complex than a program. Just pick any novel off the bookshelf and take a look at it. It is probably somewhere between one hundred and one thousand pages long, with maybe sixty lines per page. Even if we take the high end of that, which would be a very large novel, that still comes out to only sixty thousand lines of text.A program consisting of sixty thousand lines of code is small, or medium-sized at best, and could easily be written by two good developers in eight or nine months. Also, while the author of a novel never needs to worry that a single typo will make the entire book useless, a correspondingly small error in code may very well have as drastic an effect. In software, as Donald Knuth so accurately paraphrased the architect Mies van der Rohe, "The devil is in the details."Becoming one with C++ means coming to grips with a tremendous number of details. Fortunately, this task is made easier by the fact that C++ is internally fairly consistent. Once you learn a certain amount about the language, you will be able to develop an internal mental model of C++ that can serve as a framework upon which to hang more knowledge. As the framework becomes fleshed out, this internal mental model will eventually allow you to think in C++, to have expectations about how C++ works, so that a new construct or behavior seen for the first time will immediately make sense and be easily understood in terms of what you already know.That is, in learning C++ you should expect to go through the same phases as learning a foreign language. First you memorize a few words and simple phrases. Then you start building vocabulary and learning grammar and syntax rules. If you pursue your studies long enough, there comes a day when you suddenly realize that you understand the meaning hidden behind some idiomatic expression, that you can think in the new language, and then it is no longer foreign. At that point you have internalized the new language so that it is a part of you. You have become one with it, and it makes sense to you without any internal mental translation.In writing this book, I am assuming that you already have a good working knowledge of C++, that you are familiar with the vocabulary and with the grammar and syntax rules, and that you are working to internalize the language so that you can think in C++. This is not an easy task, but the rewards are great. In today's global job market, your only security is in your knowledge and your skills. You can either learn and compete, or be left behind. This applies equally to companies and to individuals.Text OverviewEinstein said that teaching by example is not just another method of teaching: it is the only method of teaching. Teaching by example is the primary method used in this book, which means that I will be presenting and discussing a lot of real, working code.ContextIt accomplishes little to present code in a vacuum. A context is needed to provide a reason for the code. The context used here is the infrastructure required to support a distributed Web application in a Unix environment. I chose this context for a variety of reasons. The Web is an increasingly important factor in modern software development. If it is not yet a factor in the software you develop, it will be. Unix, for all Bill Gates' wishes to the contrary, is widely used to host large-scale applications, and is likely to remain so for the foreseeable future. Large-scale applications are commonly distributed for both efficiency and scalability. This is a problem-rich environment, which allows me to address a multitude of issues, and all large-scale distributed applications must address similar issues. Thus, code and concepts provided in this context are both realistic and usable across a range of applications, rather than artificial toy code useful solely for demonstration purposes.Chapter OverviewChapter 2, "The Web Environment," provides a much fuller description of this context and a diagram of the architecture associated with it. An overview of the software development process and scheduling issues is presented. This chapter lays the groundwork for the code and discussions presented in later chapters.Chapters 3 through 8 present about a dozen basic utility classes that illustrate various points of design and implementation considerations and serve as building blocks for code to support the target architecture. Topics covered include concrete data types, templates and containers, namespaces, error-handling strategies and exceptions, and the reasons for and hazards of dynamic memory allocation, along with an automated solution to mitigate some of those hazards.Along the way, Chapter 4, "To Talk of Many Things," breaks the mold by presenting no code and concentrating instead on a host of development and coding issues, such as the details of organizing a large body of code, compiler-provided class members, accessor and manipulator functions, function inlining, and const correctness.In Chapter 9, "Putting the Pieces Together: Runtime Initialization," we take a bit of a break before moving on to weightier matters. This chapter discusses program initialization issues and presents a class that can be used to read runtime initialization data from an editable text file and store it in memory in an easily accessible format. This class builds on code presented earlier and serves to illustrate how these simple building blocks can be readily combined into usable pieces of reliable functionality.Chapter 10, "Program Startup and Execution Environment," presents the very detailed information on C++ program startup and memory usage which is needed to fully understand multiprocessing and multithreading issues. Differences and similarities between the two are presented along with guidelines on how to choose which to use. Shared libraries are also addressed, with specific discussion of issues involved in using shared libraries among multiple processes.Chapter 11, "Sharing Data on a Single Computer," and Chapter 12, "Sharing Data Between Computers," cover the various interprocess communication mechanisms provided under Unix, and present several classes to encapsulate these mechanisms. Although these chapters are definitely Unix-specific, the same concepts and mechanisms are also available under other operating systems, even those from Microsoft.Finally, Chapter 13, "Distributed Architectures," pulls together many of the concepts presented earlier and ties them back into the context of distributed applications in general, and our distributed Web application infrastructure in particular. Many variations on distributed architectures are presented along with brief introductions to some of the tools, such as commercial Web application frameworks and CORBA, which are useful in their development.Following the text is a bibliography. No single book or author can ever teach you all you need to know about any subject. Much of what I know about designing and writing software in C++, I have learned from others. The bibliography in this text lists those books I have found most useful and that I keep close at hand in my daily work. You may find this list a good starting point for building or extending your own reference library.Most chapters are followed by suggested exercises, which are rated on a star system to indicate the degree of difficulty. One star (*) is the simplest, and four stars the most difficult. * simple question; should take no more than fifteen minutes ** requires some thought; may take an hour or so *** requires code to be written and tested; may take a day or more **** research project; let me know if you complete one of these successfullyKeep in mind that one of Dr. Stroustrup's goals for C++ was to make writing code more fun. I hope that you enjoy reading this book as much as I have enjoyed writing it. The pure enjoyment of writing software is an important part of what we do.About the CodeI have been creating software as a contract programmer for fifteen years. During that time I have worked for large companies and small, and have been very fortunate to work on a wide variety of interesting projects spanning many areas of software, from boot code and device drivers for embedded systems to complex real-time control systems to high-level distributed commercial products. The information presented in this book is based on my own direct experience and years of study. This is reporting from the fields in which we toil, not from the ivory towers overlooking those fields, although I have tried very hard to bring as much as possible of what is useful down from those towers and out into the fields.Almost all my work over the past decade has been in C++ and has involved distributed products running on Unix machines. Over that time I have noticed many similarities among those products in terms of the problems faced and the solutions generated. I also noticed that in solving these problems, I have written very similar code repeatedly, and that as I wrote essentially the same code over and over, I actually did learn more about what I was doing and was able to write better code as a result.What I am sharing with you is what I have learned about applying a basic philosophy to writing quality software in general. I also discuss many of the common problems I have seen repeatedly, and present solutions as they have evolved over successive iterations. The code presented here is based directly on real production code. I think that seeing complete working code in the context of a real problem is the best way to teach and the best way for a developer to learn. My hope is that you will find the code useful in and of itself, and that you will find the guiding philosophy that led to that code equally useful in your daily work. Creating software is fun. Creating software that is elegant, beautiful, efficient, and cost effective is satisfying in a way that far surpasses fun. I hope that this book in some small way helps to increase your satisfaction in the code you create.The incarnation of each piece of code presented in this text was developed specifically for this book so as to not infringe on the code ownership rights of the companies for whom I have worked. In a professional production environment, code is inspected and tested with a full range of tools, which are not affordable to an individual developer. The lessons I have learned from working in such an environment are reflected in the code presented here and passed on to you, the reader. All of the code presented has been compiled and tested on a Dell Computer Corporation laptop running the Red Hat Software, Inc., distribution of Linus Torvalds' Linux version 5.2 using the Gnu C++ compiler version 2.90.29 from the Free Software Foundation, Inc. I also run Microsoft Windows 98 using Microsoft Visual C++ 6.0 Professional Edition and that portion of the code which is not Unix-specific has been compiled and tested in that environment too. Some of the issues involved in such cross platform code development are addressed in this text.On a final note, earlier incarnations of this code have been through careful design reviews, meticulous desk checking, extensive automated testing, expert peer review, and separate QA testing. I can tell you unambiguously and without reservation that, while each one of those steps was a significant factor in eliminating defects in the code, the cumulative impact of all those techniques on code quality was small in comparison to the effect of documenting the code written for this book.This was a rather startling and unexpected revelation because, while everyone proclaims the benefits of good documentation as an aid to understanding and evolving code, I have not noticed any discussions of the impact such documentation has on the quality of the code being documented. It was quite amazing how often, while writing down a description of what some piece of code was doing, it would occur to me that what I was putting on paper was not anything that I would want to recommend to other developers.Many of the insights gained from this process are shared with you here but, in my humble opinion, the best advice I can offer you on writing better code is to do a better job documenting that code. I have not personally seen any technique that offers a better payback.If you have questions or comments about the code, or about the text, or if your company is close to the Washington, DC, metro area and needs a C++ and infrastructure consultant or C++ trainer, you can reach me via e-mail at maddoxr@acm.org. You may also contact me at that e-mail address if you find a defect in either the code or the text. To the first individual who reports each actual defect, I will send a check for ten dollars, in addition to my gratitude and a brief mention in the next edition of this book. The decision as to who is first will be by e-mail time-stamp. The decision as to what constitutes a defect will be solely mine. There is, after all, some benefit to being the author!