By Dean Michael Berris
Expert Author
Article Date: 2011-02-03
There is a largely unspoken understanding between/among C++ developers that goes a little something like this: "any sufficiently complex problem can be solved by working with the appropriate abstractions". This is not a hard/fast rule but it's something that the senior C++ guys understand and internalize from an engineering perspective...
...it's not about language features, the tools, or the techniques. Notice that I say engineering instead of development. What's largely missing from the body of C++ knowledge out there is the incorporation of engineering practices. This is understandable because most of the C++ books are written to shown how to use C++ language features and not how to engineer proper abstractions and algorithms. Is there hope yet for the people who miss the point when they say "C++ is over because language X will kill it"?What makes great software teams and products work is largely not the technology used behind it. It's a combination of factors that determine the likelihood of success and of staying power:
- Opportunity - is the product positioned and developed to take advantage of an opportunity for profit/adoption? This is largely a function of timing and of positioning more than it is a matter of technology. Languages like Javascript and software like web browsers are largely a function of the opportunity to develop a new medium/market through which much of the innovation would happen. Had Javascript been developed and shipped outside of a browser it wouldn't have grown to be a popular language by any standard. There was an opportunity and those that execute well enough to grab that opportunity usually succeed.
- Execution - a poorly executed product is not going to have staying power. There are a ton of examples of this in many different spaces that I don't think it's worth mentioning any of them.
- Iteration - being able to add features or evolve the product in a consistent and predictable manner makes for great staying power in the market. Lots of examples here too so I'd rather not mention any.
- Quality - it's largely impossible to describe what quality is, but you know it when you see it. It's that general "feel" you get that this thing you're looking at or using is of a high quality. It's almost impossible to quantify quality which is why it's so important as a differentiator and as a factor for success of any endeavor not just software.
With these in mind you'd think that C++ would score really low on these points. Let me list down a few reasons why I think so:
- C++ was developed largely at a time when C was already "sufficient" for all intents and purposes. Other programming languages already featured object-oriented programming and Lisp even had a good model for functional programming and imperative programming idioms to allow anybody to write great software with it. There was not an opportunity to create a new programming language that built on top of C because other programming languages were already available for doing things as far as programming was concerned.
- C++ wasn't executed in a manner that you would call "well". It was meant to be bolted on to C as a means of "formalizing" the object-oriented paradigm and introducing it in "familiar" C terms. The first implementations were largely bloated and poorly done that it was thought of as an exercise in futility.
- The first C++ version debuted in 1983. This was largely a research project and not really a commercial product. The time between the first version and the international standard was a good 15 years - the first official ISO C++ Standard was published in 1998. The first addendum to the standard was in 2003 and the next version is supposed to come out this year. This is hardly iterating in a consistent manner - unless you think 15 years is a good time frame for iteration.
- C++ has drawn a lot of flak for being a "too complex" or "too rich" a programming language. It's far from a simple programming language. And even if there is an international standard out there on what the standard C++ language is, it's not until recently that the majority of the compilers available to programmers in general actually follow the standard to the letter. For this the quality of C++ implementations are actually suspect.
If you read the above points you'd think I've changed my mind and that I've turned my back on C++. It would seem like I'm throwing stones at an easy target here. However though it is important to point out that the reason why C++ hasn't died yet and why it would take a while for it to get killed - if it will ever be killed which I am skeptical about - has something to do with the external factors other than the technology. I'm talking about the software engineering practices that C++ above all the other programming languages enables: developing rich abstractions and implementing succinct algorithms that operate on these abstractions.
Precisely because C++ is a huge and largely permissive programming language, it was designed to enable people to model solutions in a richer manner than how C would have you constrained in doing. It assumed that programmers would know what they're doing instead of being dumb kids that need to be prevented from shooting their feet. It's a tool that takes time and effort to be able to wield effectively but when you get to that point of knowing how you can leverage the features to model your abstraction and enable your implementation, it's pretty powerful. When C programmers were fine with just structs and pointers, C++ gave programmers the ability to model dynamic polymorphism, generics, and more intuitive modeling with the use of namespaces, references, value semantics, and operator overloading. The difference between C and C++ is like having a toolbox for fixing cars and having a toolbox for fixing jets: for all intents and purposes, the toolbox that has more tools would allow you to do more things easily than the one that has less tools.
The point on execution is largely a good thing: the first implementation didn't need to be perfect, but it needed to be believable and an effective proof of concept. If someone came up with a programming language implementation that is already largely perfect to begin with (think Common Lisp, C, and more recently Python) then the room for improvement is a lot smaller than if a good idea was implemented with a proof of concept that needed improvement. This was how Linux started: a simple attempt at a PC-based UNIX-like operating system which was not more than a simple kernel when 0.1 was released. It's the same with DOS. Although there wasn't an obvious opportunity for greatness, there was enough opportunity to build traction and a following while the room to grow is still huge. Because the opportunity was really manufactured by having a poor initial attempt at an implementation of a good idea, it breeds involvement and bigger opportunities for a larger win in the long-term.
Having an internationally recognized standard is one thing but I think if C++ was rushed into standardization too early it could have nearly killed its potential. Consider the version of C++ that was debuted in 1983 - imagine if there was an international standard before templates were introduced and properly implemented. That would have made C++ no better than Smalltalk in terms of OOP features, and Smalltalk would be arguably a better OOP implementation. Because the first standard was developed when there were enough people around the world investing in and building upon the (admittedly small) ecosystem of tools and platforms available at that time, there was greater incentive to pull the standardization effort off. And because the standard was built on industry feedback and actual user requirements, it better reflected the state of the art than had the standard been developed in isolation. The same is true for the C++03 addendum and the C++0x current final committee draft. There are some things not worth rushing and the standard having a good amount of time to be exercised and used in the wild is actually a good thing.
For a rich programming language C++ is getting a lot richer - and that's a good thing. I'll go back to that analogy of a car maintenance toolbox and a fighter jet maintenance toolbox: if you needed to build a bigger/better/stronger fighter jet, I doubt it would be wise to build a new toolbox off the car maintenance toolbox. And this is where the evolution factor comes in handy: as in evolution as defined by Darwin, you need to have enough of a population of samples to be able to generate better offspring and have a better chance of surviving in the next set of generations. C++ is evolving at a time when multi-core programming is slowly (if not already) the norm to properly define the semantics of threading. Because of the cross-pollination of ideas with/from functional programming languages C++0x is getting inline function object definitions (lambda's/closures). When template metaprogramming and a richer type system is making itself a more integral part of the C++ programming experience, things like 'auto', 'rvalue references', move semantics, and goodies like decltype and template typedef aliases just makes C++ that much more powerful.
What's been largely untouched yet in this post is the fact that programming with C++ is more an engineering endeavor more than it is a programming endeavor. If you think about it a little, other programming languages makes gluing things together and calling it a day easier. Your solution might not be robust in the face of strict requirements on inputs and/or predictable in the face of exceptional instances (for the case of dynamic programming languages), nor be efficient in the use of available resources (in the case of garbage-collected and/or scripting languages, but for some cases that might just be what you need. People still write shell scripts and python scripts to do the odd little thing that would benefit from scripting - but anytime they need to be controlling the resource usage or facing performance issues, they reach for the tools that enable them to model their solution cleanly and have pretty much the most powerful machine code they can generate.
I think what sets apart the senior C++ programmer from other programmers is that because C++ is a language that forces you to engineer your solution in an intuitive manner rather than just clobbering together a set of tools already available at your disposal. In some cases duct-tape solutions work until you need to start replacing the ducts themselves - and for that matter duct tape is the worst thing for joining ducts together. Looking at most of the successful C++ based applications out there in the wild (and even hidden behind monster enterprises) you will find that they succeed mostly because:
- They take advantage of an opportunity that is either obvious or one that is being manufactured by them.
- They are executed as engineering projects that take time to think about the abstractions and algorithms dealing with these abstractions.
- They are implemented to be iterated upon and maximizes the investments as far as time/resources are concerned in the building of that piece of software.
- The quality of the implementation is held in high regard not only in terms of internal quality but also as far as external quality.
It takes a certain mix of pragmatism and discipline to be able to wield C++ in an effective manner. But when you get a group of these proficient C++ developers together that hold the engineering practices in high regard you almost always just get great software in return.
It's not C++ that makes the software great - it's the great people who make C++ software work.
Comments