When I first moved to New York City, many of my friends asked me how many famous people I have run into. While I did run in to Larry King at FAO Schwartz once, I am not aware of any other famous people that I have run into in the course of my daily wanderings.
Of course, the key point is that I would have to be aware of them. I am not always the best resource for current pop culture information, and I am particularly not knowledgeable about sports. I was surprised (and later poked fun at by several colleagues) when I saw a guy who lives in my building (a really nice guy who I would bump into in the lobby occasionally and who was always very friendly and outgoing) on television. It turns out that he is a fairly well known pitcher. So much for knowing your neighbors.
NYC Subway Entrance
I was riding home on the subway the other day, and as usual I was sitting reading a book. I happened to be reading Blink by Malcolm Gladwell. At one of the stops along the way, a man walked in and sat down next to me. He commented that he really liked that book, and I agreed. He then commented that his brother is in the book - he is the doctor in Chicago (Brendan Reilly).
I have no way of verifying the truth of his statement, but he didn't appear to want to use it as an introduction to additional discussions. He just picked up his paper, and began reading as well. Thus, I am inclined to believe his claim. Of all of the brushes with "fame" I have had, this random encounter goes down for me as the most personally relevant.
I guess it just shows that you never know who you are bumping into when you ride the subway. With 124 million riders in a typical month, the person sitting next to you just could have a relevant and interesting story. I'm not sure why I felt the need to bring this up - I just thought it was random in a very interesting way.
So far, I have covered two important aspects of software design that will impact how this software will evolve into the future. A brief recap:
Evolvability. When developing software, you are fighting a battle against the combinatorial mathematics that govern the complexity of any respectably sized software project. There are simply a huge number of possible approaches. Most of these approaches do not work. Of those that do, some will be better, either in terms of security, performance, maintainability, etc. Genetic algorithms are a special case of this - this is a technique for rapidly covering a problem domain without investing the man hours to actually code each separate solution, and may take approaches that seem completely non-obvious to the developer, but are in fact preferable to the straightforward approach that a human would apply to that problem. However, even if using a genetic algorithm to crawl your problem domain is not practical, there are lessons to be learned from the implementation of evolution in biology. For example, it is a bad thing when modification of a gene at locus A confers some evolutionary advantage, but simultaneously presents a phenotype that is negative. The same is true for software. At a granuar level, object oriented programming helps to solve this problem. At a higher level, there are architectural approaches that make this easier. What is important is the underlying ideal.
Parallelism. There is no question in my mind that massively parallel algorithms are going to be key to success in the future, even more so than they are today. Being able to design systems that are massively parallel will not only allow your software to take advantage of hardware designs that increase computation capabilities through parallelism, but they present a whole new set of opportunities to interact with external processes and services in a way that is non-blocking and more intuitive. Why should I wait for my email client to check email before I can read email that I have already downloaded?
On top of this, I would add a third category, which does not have as direct a biologial analogy as the others, but is nonetheless extremely critical.
User Experience.
From user experience, I am thinking of two perspectives. The first is the overall appearance, which is how we frequently think of UI Design. Given a particular screenshot, implement this in code. Why is this experience important? Here, we are trying to convey a sense of quality, and drive a strong initial first impression. Depending on the software you are creating, this may be more or less critical. Some software is of the nature that people have to use it because there is no real competition, or who make up for this first impression with solid interaction design. But I believe it also drives how you feel about using the application. Does it feel modern? This may make me more excited about using it. Does it feel of high quality? This will make me trust the software more.
Windows Media Player 11 UI Design
The value of this experience is important, which is why screenshots are actually interesting to post on new products.
The next perspective is of user experience, or interaction design, which is different from that I am calling UI Design. Are you able to get your work done in a more efficient manner? Are your options exposed to you in a way that you can discover them? Is the act of navigating the appliation effortless and logical? For example, consider that we are designig a VCR. Rather than sending one group away to develop a list of features (such as multiple timed recordings, playback, and manual recording) and another to design the appearance of the device itself, can we approach it differently and design it first from the perspective of interaction? Yes. We can think in terms of scenarios. One important scenario is setting the clock so it is not flashig 12:00 indefinitely! Another is the scenario where somebody wants to record what they are currently watching. The final scenario is one where we want to set up several programs to record on an ongoing basis. Given these scenarios, we can start to explore them more thoroughly. We would like to understand why so many VCRs blink 12:00 all of the time. Can we solve the first scenario more easily? Is there a time source accessible to our VCR that doesn't involve the human at all? If it must involve a human, can we design it as part of the setup experience, understanding that nobody is interested in having a flashing 12:00 sign? But if we make it part of the setup experience, now we are preventing people from using their new VCR to play a video tape right away, until they answer a bunch of our questions - should we postpone that experience until the user requests it? If we do, how to we expose a way to do it at the user's convenience? Do we expose a hardware button? Do we post a notification that can go away? We haven't even exhausted our set of questions about the first scenario, and already we have to make some difficult decisions. However, this is time well spent, as this affect everyone who uses the VCR.
As I continue to evolve my blog, these are the three areas that I have run into time and time again as being important skills for the software practicioner (including myself!) both today and going into the future. To solve the hard problems that await us, we need to be able to search the problem domain more efficiently. We need to support parallelism, which will be supported more and more completely in hardware as time passes. And we need to provide a positive user experience that is focussed on fulfilling users' goals.
When discussing the evolution of software, I have spent some time discussing genetic algorithms. When trying to think 10 or 20 years into the future, these algorithms provide us with a proven way to explore a large problem domain (caused by the combinatorial nature of possible solutions to a software problem) with much greater efficiency than an exhaustive search (which may be entirely unfeasible). I believe that this is going to grow to be more and more important over time, as the problems we are hoping to solve have less and less obvious solutions.
An area of much more immediate concern is how to mold software to the shift in focus from extremely fast processors to many processors.
A brief digression: Back in the 1990's, I received an email from a colleage who was working on an application that was having performance issues. This was a Visual Basic (6.0 at the time) developer who did not have academic training as a developer. This individual had heard that C++ enabled developing multi-threaded applications, and that multi-threaded applications were objectively "better" than the single-threaded applications that were possible in VB. So, this person contacted me for some "quick" information on how to port the application to C++ and make it multi-threaded, because this would certainly solve the problem quickly and effectively without having to spend all of that time revisiting the architecture and the algorighms used. Unfortunately, it really wasn't that easy. The application was being run on a single processor machine (even dual processor machines were comparatively rare at the time), and the problem wasn't that the thread was blocked - the problem was that it was solving the problem in a computationally intensive way. Adding multiple threads would only exacerbate the situation - in addition to a fully loaded CPU, multiple threads would add the additional resource pressure of context switching. I told this person to leave it as a single threaded application and look for other ways to optimize, since in this scenario parallel processing was not going to offer any benefits.
This continued to be true for quite some time, and the applications we have on our desktops today certainly reflect that philosophy. I am writing this on a single-processor machine. At home, I have one computer with two virtual processors (hyperthreading), but the rest have a single processor. Since software is dictated in many ways by the hardware used by both the customer and the developer, massively parallel applications are comparatively rare.
But single processor machines are starting to approach a limit. My 3.6 GHz Pentium 4 has a gigantic heat sink sitting on top that whisks heat up using both copper and some kind of compressed fluid to an array of fins that a fan blows directly over the top of, and I still get a blinking processor temperature warning light from time to time. I already don't have to invest a lot of money heating my office, because my computer does a good enough job of that on its own. I really don't want processors running faster and hotter - I just want them running faster. That requires additional processors. We are already seeing dual core processors.
AMD Dual-Core Processor
I think we can safele expect the trend to continue in this direction.
Again, this process takes its cue from biology. The human brain is able to solve incredibly complex problems. It is estimated that it can process on the order of 2 * 1016 computations per second. It is able to compute at this level without generating extraordinary amounts of heat becaues it is massively parallel - the computation is distributed throughout the brain, and not run through a single "super" neuronal computation facility. The up side is that you can scratch your head without receiving third degree burns. The down side is that you have to invest in tools such as a stove or a microwave, rather than just popping food in your mouth and thinking really hard in order to cook it.
The massively parallel nature of the human brain allows it to do some very impressive pattern recognition tasks - tasks which we have yet to fully replicate on computer hardware because it does not support the same number of cumputations per second. However, in the next few decades, we will most likely reach this level of computation, and we will most likely achieve this through creating our applications to be massively parallel.
The fact remains, however, that creating multi-threaded applications is really hard to do well. In the 1.0 and 1.1 versions of the .NET Framework, you had the option of either creating threads on your own, or leveraging the managed thread pool (which you could do fairly easily using delegates, and not even have to be aware of the existence of the pool). The 2.0 version of the framework introduces the BackgroundWorker class to make it even easier.
Side note: from a user experience point of view, if you are developing Windows Forms applications, you should be intimately familiar with the options for running on a separate thread, as blocking the primary UI thread to do some long-running work is really bad form.
There is still room to evolve the platform, however. We still have to publish best practices and educate people about deadlocks and race conditions.. There is not a common platform for developing and parallelizing algorithms to distribute across hardware resources. (Microsoft Research is working on a project called Dryad whose goal is to do exactly that.)
In the interim, I think it behoves every developer to begin considering the impact of the migration from one really fact processor core to many processor cores. In my opinion, this is going to be a hugely important skill in the coming years, and it is already relevant today.