Wednesday, February 28, 2007

Java and its insecurities

Why are there so many Java cheerleaders out there telling us that its so much faster than C/C++? I feel like for every one article complaining about how Java is too slow, there are dozens that spring up explaining the the opposite?

I think there is a real Java inferiority complex going on.

Tuesday, February 27, 2007

Finding bugs that don't want to be found

I'm a big complainer when it comes to modern IDEs and debuggers. They mostly suck. I've got a good example of how they suck.

For the past week I've been working on a bug which only reproduces about 1 out of 500 times I run my validation test. It takes about 30 seconds to run the test, so even if I script the validation, it still takes minutes to reproduce the problem. Obviously there is some crazy race condition going on.

So where would you start? At this point nearly every debugger in the world is useless. You cannot sit there and run your program 500 times, it would take forever. And even if you did manage to reproduce it in the debugger, if you step over you precious bug you're screwed.

Well I started off by adding assertions... everywhere. Assertions are kind of like printf's except they only do the printing on a condition and when they get hit, they normally exit the program. One benefit of assertions over printfs is that you can keep them in your code. They also serve as documentation for other programmers who comes along.

I was able to get my assertion to be hit. But it wasn't enough. In order to figure out what was wrong I needed to know the state of some data structures when the assertion was hit. So I needed to use printfs... there was no other way to do it. I started dumping lots and lots of data.

After I inserted my logging code I tried reproducing the bug again. Every run I would dump about 5MB of logging data... for 200 runs thats 1GB. After about 250 runs I hit my assertion. I looked through the logging output and found my bug... I was locking a data structure just a couple of lines too late. I moved the lock up a couple of lines and the bug vanished. It was a two-line fix to very hard problem.

In a perfect world finding this bug could have been much easier. It would be really nice if when the assertion was hit, a debugger would automatically be launched on that program. Once the debugger was launched I could view all of the data structures that got corrupted. In this particular case that wouldn't have been enough. I also needed the execution history of how the data structure got corrupt. However that too would not have been enough because there was another process which was writing to the data structure too. I also needed to know know how that process was changing the data structure....

To solve this problem I not only needed to know what code I ran, or the data structures when that code was run, I also needed to know how those data structures changed over time. Thats where the difficulty of debugging comes in, figuring out when and how data structures change.

Can visual studio help you with this? How about gdb or eclipse? No, no and no. They all suck at debugging and not a single one would help you get closer to finding the problem. I need something else...

Friday, February 23, 2007

How Idiots Develop Software...

I hate all of the modern software development tools. Nearly all of the IDE's out there focus on writing code, even though about 90% of your time is spent debugging code. I think the motivation behind this is that IDE developers have no idea how to make a debugger, so they help us with writing code so we can litter our code with printf's.

I'm sick of using printfs. Why is it that developers still use them even though its a 30 year old technique? Every time you want to find something out about how your code is working, you have to find the printf insertion point, recompile your entire project (which could take minutes), and then re-run the program until your printf gets hit. And what happens when the printf doesn't get hit, or it doesn't spit out enough information? Well then you have to start all over again. If you repeat this process enough, pretty soon your code is littered with printf's and the debugging output becomes a nightmare to analyze.

I got more gripes with modern debuggers....

One of the biggest advances in the new IDEs are error highlighting. Don't get me wrong, error highlighting is cool. But how much of your day is spent tracking down hard to find syntax errors. For me its about 20 to 30 seconds a day. So thank you error highlighting! You saved me 2 hours last year!

Seriously is error highlighting the best that you can do? I've spent days, weeks, months (years??), tracking down impossible to find memory leaks and corruptions, race conditions, and bugs in complicated control flows. I spend a negligible time amount of time tracking down compile-time bugs.

Today IDEs either provide no UI making it difficult to browse and write code (ahem gdb), or there's so much UI that it waters down all of the features (ahem eclipse). Visual Studio is better than both, but I could still spend a week explaining why it sucks. None of them make it easy to browse code without clicking a half-dozen menus. None of them make it easy to track race conditions. Some of them help you with memory corruptions (valgrind) but are a bitch to setup. None of them really help you understand how your code works.... displaying the class hierarchy is a nice visual touch, but is pretty useless when trying to track down bugs.

I've got some ideas on how to make these debuggers much much better. Maybe later on I'll try to explain my new ideas techniques and formally analyze why each IDE sucks, but for now I'll just bitch.

Wednesday, February 21, 2007

Why do software tools still suck?

Why is it that software tools have only inched along in the last 15 years? Fifteen years ago we were using similar debuggers and text editors. Fifteen years ago the software development cycle looks strikingly different to todays. So where is the innovation in software development?

Well there has been a good amount of innovation in software development, it just hasn't been in the tools. In the past fifteen years we've seen the rise of managed code like Java and Microsoft's CLR. We've seen software modeling tools like UML. We've also seen a rise of powerful scripting languages starting with VBScript and now Python, PHP, and the rest. More recently we've starting seeing static analysis tools like Coverity and Klocwork.

Of all of the technologies listed above, the only one which could accurately be described as a tool is static analysis (which I'll get to later). Everything else is a language or meta-language. So the real innovation in the past 15 years has been languages and the extra features that they support. The motivation for language innovation has been the travesty which is C/C++. Of the thousands of languages in existence C/C++ is probably the most hated [see here here here here ...] .

In the newer languages they've tried to build on all of the good things that were in C/C++ and strip out all of the crappy parts. Some advantages of the newer languages are easier memory management, syntactic sugar, and the supplied libraries.

Without a question the real advance in these languages are their libraries. Nearly every single new language that comes out also comes with a huge set of powerful libraries that make application development much much easier. Nuff said about that.

Complexity may be managed a bit better in the newer languages by pushing programmers to use more object oriented design. However, object oriented spaghetti code is often more unreadable then a flat design simply because OO programming gives the impression of modularity.

the newer memory management models are also not fool-proof. In many languages you can still corrupt memory in a similar way that you can in C/C++, however you get a programmer friendly exception instead of a crash. An end user doesn't know or care about the difference between an uncaught exception and a crash.

In some languages there are built-in types to handle multi-threaded constructs. The only real advance in multi-threading has been the use of moniters. I have yet to meet anyone who uses moniters in practice and they are really just syntactic sugar, not a real advance in programming. But most importantly when you have a multi-threaded application you still get the same race conditions and dead locks that you got in C/C++.

It isn't enough to focus on languages. If we really want to advance software development to the next level and create more reliabile and feature-packed software faster, then we need better tools. The main focus here should be handling complexity, error diagnosis (aka debugging), and multi-threading.

I'm going to stress multi-threading because if the semiconductor industry continues on its current track in a couple years we're not going to be able to write single-threaded applications. Processors will come with many cores and we're going to have to learn to take advantage of them whether we like it or not.

So do I have suggestions on how to get us out of this rut? Of course I do....

Tuesday, February 20, 2007

Its the tools stupid

Think about how we were developing software fifteen years ago. For the mathematically handicapped thats 1992. At that time Visual C++ 1.0 was hot off the press and you most likely didn't use it. You were probably using ed, vi, emacs, or some other cult-following editor. All of the editors had syntax highlighting. The modern debuggers had features such as watchpoints, single stepping, and variable inspection. However you probably never used any of these features. You would be considered state-of-the-art if you used breakpoints. Back then the king of the debugging world was printf.

Now lets look at today. Compilers today are much better. They have fewer bugs and are much more standardized. The biggest breakthroughs in editors have been automatic code-completion, integrated documentation, and error highlighting. The biggest breakthroughs in debuggers have been conditional/scriptable breakpoints (which no one uses) and a little bit better GUI design, and more recently multi-core debugging. It is shocking, but from empirical evidence the most common debugging technique in the world is still printf!!

Why is it that the tools have only inched along? Thats coming up next, but I'll tell you now that our modern tools are still not good enough. The fact that printf is still so widely used is a key indicator that we haven't changed much at all in the past 15 years.... more on that later.

Monday, February 19, 2007

Why Specifying Software Never Happens

In my last post I asked why is it so hard to specify a computer program before you start writing code? I mentioned how architects can draw blueprints for an entire building without laying a brick, and how scientists can design nuclear weapons without testing them. However computer programmers have huge difficulty grasping what needs to be done before they do it.

There are several reasons why programmers cannot specify their work early on in the process, however most of the reasons are hand-wavy and are part of the same old story we've been hearing for years. So here are the hand-wavy (but important) explanations first, then we'll get on to the real meat of the issue.
  1. Poor Internal Communication
    This is obvious but is something that consultants love to point out so they can charge $300 an hour. The main problem here is that if a developer/customer cannot properly communicate what he wants, then he'll get something else altogether.
    Every organization has communication problems. Ideally we should wire all of our brains together so everyone knows what everyone else is thinking every instant. Until that happens we'll over pay consultants to tell us how to "refactor the enterprise". Besides, there is nothing specific to computer programming here.
  2. Lack of precedent
    Generally whenever a team creates a computer program it is piece of software that does something that no other piece of software has done before. If there was another program which did the same thing, then there would be little reason to reinvent something that already works. Everyone has heard of the not invented here syndrome, but in practice, things get reused if they meet quality standards, are not prohibitively expensive, and have the appropriate software license. Sure there are me too products out there, but most of those products were developed because they didn't meet one of the three above requirements.
    Whenever anything is created without much precedent, it isn't easy to figure out how it should work. When making a building architects already understand all of the basic mechanics of what is physically possible. Scientists already understand the reactions necessary for a nuclear explosion. However if a computer programmer is writing a brand-new piece of code, there is no one telling him how it will work best. Of course as developers we always try to make use of precedent by reusing libraries and sharing code. However at some point you're going to be writing some code that no one has written before.
  3. Complexity
    This is everyone's favorite excuse for failing projects, but really its horse shit. It like a kid complaining "I can't do my homework cause its too hard." Software development is hard. Complexity is a bad excuse why projects fail not a reason. Complexity will provide a good segway into my next and final reason why systems cannot be specified earlier in the development process.
My so-called hand-wavy explanations don't explain the full problem. Communication issues can be solved with proper communication and management. Lack of precendent and complexity are complaints more than reasons that projects fail.

I believe that there is one major reason why software engineers do not and cannot specify their products. It is the same reason that the Waterfall Model is broken and also the reason why most software projects end in failure. The reason will be the main focus of this blog and I'll tell you now that it isn't agile programming (though I have nothing against agile)...

The Waterfall Method and Process

Most computer programmers have had to deal with 'process' at some point or another. To some, process is an organized way to get abstract ideas into code. For others process is an unnecessary bureaucratic slowdown. Many see it as a way for managers to keep themselves busy and avoid real management. Regardless of what your general feelings towards process are, there is probably no process that is more nonsensical to computer programmers than the Waterfall Model.

The Waterfall Model was one of the first computer programming processes that really caught on. It dictates several stages of development. I'm not going to give a primer on the Waterfall Model, Wikipedia can do a better job than I. However the most important feature of the waterfall process, and the reason it is doomed to fail, is that you must know everything about what you want your computer program is to do before you start writing code. In nearly all applications of computer programming, it is impossible to know what a computer program can do that early on in development.

Development is a fluid and iterative process. You try something, it works well, and you expand on it. You try something, it doesn't work, and then you try something else. I have never worked on a project where we knew everything up front. There was always some experimentation and there was always some backtracking to get things working properly.

However we must ask the question, why cant we know everything upfront? Architects can generate all of the blue-prints needed to build a sky-scraper without laying a single brick. Today nuclear engineers can design nuclear warheads without even testing them. So what makes computer programming so different? Why is it that computer programmers are so special that we cannot predict what the outcome of our projects will be?