Role Models for Success

Douglas C. Schmidt
C++ Report
February 1996

Last fall I taught a fourteen week course that covered many practical aspects of designing and implementing object-oriented software. The course focused on developing reusable components using design patterns, frameworks, and C++. The goal of the course was to impart good software development practices through extensive case studies and programming exercises.

The final exams and final programming projects are done. In between battling snowstorms in St. Louis, I've been reflecting on the lessons I learned while teaching this class, and relating them to other teaching experiences I've had during the past eight years. My current teaching responsibilities at Washington University center primarily at the graduate and undergraduate level. I've also taught scores of courses and tutorials on object-oriented design and programming with C++ for professional software developers. In this month's editors corner I'll cover several important lessons I've learned while teaching C++.

Lesson 1. The C++ you teach in the mid '90s is not the C++ you learned in the mid '80s.

The emerging ANSI/ISO standard greatly improves the clarity of the C++ language definition. At the same time, the standardization effort has introduced new language features and components that must be mastered to use C++ effectively. I believe the most pervasive impact results from exception handling and the Standard Template Library (STL). These features and components significant affect the development of C++ components, frameworks, and applications.

Many '80s vintage C++ libraries and frameworks (such as NIHCL and ET++) were influenced by Smalltalk and other inheritance-based models for designing object-oriented components. The advent of parameterized types and STL has changed this model considerably. Thus, '90s vintage C++ class libraries and frameworks (such as ObjectSpace's System and RogueWave's next generation Tools.h++) are influenced by the generic programming model of designing object-oriented components. I suspect that template "traits" idiom will be used frequently in '90s vintage C++ programs.

Exception handling is another feature that significantly affects C++ program development. Many '80s vintage C++ programmers manage dynamic objects referenced by pointers allocated on the run-time stack. Exception handling renders this style of programming obsolete if robust resource reclamation is needed when errors occur. Thus, '90s vintage C++ programmers must learn successful strategies and tactics for writing exception-safe programs. I suspect that standard C++ library "auto_ptr" class will be used frequently in '90s vintage C++ programs.

Lesson 2. Stress good software design and programming concepts more than C++ features.

One of C++'s greatest strengths is its expressiveness and breadth. Features like functions, classes, inheritance, virtual functions, and templates span multiple programming paradigms. While this makes C++ applicable in domains ranging from embedded systems to global communication systems, newcomers can easily be overwhelmed by the sheer scope of the language feature set.

I've programmed extensively with C++ as it has evolved over the years. Therefore, absorbing these new features and components has been incremental and relatively painless. It's tempting, however, to forget how imposing C++ can appear initially. Teaching C++ to junior-level undergrads forced me to wrestle with how to introduce and motivate the C++ feature set concisely and effectively.

During the past eight years I've tried many different ways of teaching C++. I originally focused on teaching C++ language features. However, I found that this approach encouraged the use of obscure and error-prone C++ language features (like user-defined conversions and class-specific overloaded operator new). In general, "feature-centric" programming styles yield unwieldy systems that are overly subtle, non-portable across C++ compilers, and hard to maintain.

More recently, I've focused on teaching C++ by stressing design patterns and language idioms. In this approach, I emphasize how design forces shape software architectures and influence the choice of certain C++ language features. For example, requirements for release-to-release binary compatibility discourage the use of inline functions and macros. Likewise, requirements for run-time efficiency encourage the use of templates vs. dynamic binding.

I've found this pattern/idiom-centric approach to teaching C++ quite effective. In particular, students focus on more on the strategic aspects of their designs, which generally yields more extensible, decoupled, and maintainable programs. In addition, by focusing on patterns and idioms FIRST, students are motivated to use key C++ features (like classes, templates, inheritance, and dynamic binding), rather than the more esoteric features.

Lesson 3. Provide good role models for developing quality software

One of the most poinient lessons I've learned from teaching C++ is that we need better role models for developers who aspire to become expert software designers and programmers. In particular, many of my students over the years had little prior exposure too systematically scrutinizing good software programming and design practices. I believe my experiences teaching C++ are a "micro" reflection of a "macro" problem faced throughout the software industry.

It's no surprise that newcomers to C++ often struggle initially with features like pointers, dynamic memory, and the absence of run-time bounds checking on arrays. With proper guidance, however, most students of C++ master the basic language mechanics and evolve into proficient programmers. Many good books, magazines, and online resources are available to serve as role models for developers who aspire to become expert C++ programmers. Good role models are important -- they help developers internalize idiomatic programming strategies and tactics that were traditionally learned only through painful trial and error.

Throughout my teaching career, however, I've found that many developers have a much harder time evolving into proficient object-oriented designers. Good designers often exhibit an intuitive, aesthetic quality in their work. Capturing and conveying this quality is hard using traditional methods of education. Moreover, until recently it's been hard to find good resources to serve as role models for developers who aspire to become expert object-oriented designers. A key contribution of patterns to the software industry is its focus on capturing and articulating the "ageless" wisdom of good design and programming practices.

The dearth of expert software designers has become a serious problem in domains ranging from telecommunications, health care delivery systems, financial services, and transaction processing. Due to increasing pressure to reduce business costs, enhance application functionality, and leverage hardware advances, software systems have become more complex and more safety/mission critical. From my experience developing large-scale commercial telecommunication and distributed medical imaging systems, projects that lack coherent, decoupled software designs almost certainly go awry.

To succeed in an increasingly competitive software marketplace, it's imperative that software professionals develop and hone their design and programming skills. To be most effective, this learning process must start early and continue throughout a developer's career.

Unfortunately, many undergraduates in computer science receive inadequate education and mentoring in good software design and programming practices. Instead, most university students receive extensive training in theoretical models (like Turing machines), formal methods (such as axiomatic language semantics), and algorithmic analysis techniques (such as solving recurrences). While these topics are an important foundation, it's increasingly imperative to broaden the scope of computer science education.

In many universities, there's a conspicuous absence of systematic coverage on key topics such as software architecture, design patterns, distributed and concurrent program development, object-oriented design, and system evolution strategies. As software continues to become more complex it is increasing necessary to inculcate these topics into our undergraduate and graduate curriculum. If we want to make serious progress towards alleviating the "software crisis," we need to get serious about teaching these topics rigorously from the start.

At Washington University, we've begun restructuring our curriculum to address these concerns. If you're interested in seeing what we're doing, the lecture notes and programming exercises for my course on object-oriented software design with patterns, framework, and C++ are freely available online at the following WWW URL:

Lesson 4. Successful developers must go beyond object-oriented design and C++

Becoming an successful developer in the '90s requires much more than knowledge of object-oriented design techniques and C++ programming language features. Systems are increasingly built by interconnecting powerful computers with high-speed networks. Therefore, it's crucial to understand concepts like concurrency control, persistence, distribution, and resource sharing. This month's C++ Report features articles by Sean Leary on a framework for multi-threading and Marina Kamele on managing persistent shared memory objects. Steve Vinoski and I examine concurrency models for programming distributed object servers using C++ and CORBA. In addition, Tom Cargill takes a look at Java from a C++ programmer's perspective. The surge of interest in Java is driven largely by its role as the premiere programming language for World Wide Web applets.

I hope that these articles, along with our other excellent columns and articles, serve as good role models for your future growth as C++ developers!

Back to C++ Report Editorials home page.