Most bugs that I fix in the DVDMaker UI are fairly benign, but yesterday I fixed one that could have had more severe consequences, as noted in my checkin mail:
Our next sin is the one that I've certainly been prone to.
Long ago my wife and I owned a house east of Renton, Washington (those who know about Renton at that time can probably understand why one would say "east of Renton").
Like many homes, this one had had various indignities committed on it by the previous owners. One of the most obvious was what can only be described as a "lean-to", constructed out of surplus Boeing shipping containers and shielding the washer and dryer from the rest of the garage.
After dealing with cold and dirty feet for a few months, we decided to convert the space to a real room, with features such as a floor, a laundry sink, a ceiling that was actually attached to the joists, etc. The framing went quickly, but when it came to the point of finishing the drywall, we ran into a problem.
My wife and I had very different ideas of how smooth a wall should be before it was painted. She wanted it to be mostly smooth, while I spent a fair amount of time with a light at an oblique angle, trying to get it really smooth.
I did the bulk of the drywall finishing myself in that room.
And after it was all painted, it turned out that it didn't really matter. Her standard was fine.
Which leads us, in the usual roundabout way, to our destination:
Sin #4 - Premature Optimization
Or, in other words, spending time on things that don't really matter in the end.
It's happened to all of us. You're in the middle of writing a class, and you think "a linear search of an array just isn't going to be fast enough here". So, you spend some extra time, and you use a hash table, or a tree, or a binary search, or something like that, and when you're done, you say to yourself, "now *that* isn't going to cause any problems".
And then later, when you're getting close to done, you run your code through a profiler, and you find that a) the array never has more than 3 elements and b) the code is spending a ton of time elsewhere in the code.
You wasted the time that it took you to do the optimization (bad), and you may have ended up with code that is considerably harder to read (worse), depending on how much optimizing you did.
How do you avoid this? I have two bits of advice:
I'm happy to be able to announce something that has been in the works for a fair bit of time.
MSDN documentation is generally pretty good, but it sometimes misses some important information, and it's hard to get that information where people can see it, and back to the authors.
MSDN Wiki allows comments to be added to msdn topics. I just added one to the main page for the Regex class.
Kudos to the team for making this happen.
Microsoft Robotics Studio.
Looks interesting. Uses a CLR 2.0 base, though it's not clear to me yet where the MS part runs on the robot or whether it runs on a separate windows computer.
[Several readers pointed out that I made a mistake in phraseology, and didn't say the thing I meant. Thanks to them for knowing what I wanted to say more tha I did.]
Thanks to all who have commented on the previous sins, and to those who have written their own lists. I have avoided reading them, but I will take a look when (if...) I get done with my list, and I'll write a summary post linking to them, and likely listing the ones that I would have put on my list if I'd only been a bit smarter and a bit more thoughtful.
Back when I was a pre-teen, I thought I really knew what was going on. I didn't need my parents advice on what to eat, or who to hang around with, and I *certainly* didn't need their advice around oral hygiene.
So I didn't brush my teeth. Oh, I'd rinse my mouth out, but no actual brushing.
This didn't cause any problems - my teeth were fine when I went to the dentist. No worries.
For a year or so. Then I had to have 4 cavities done in one fall. Big cavities. Cavities that weakened my teeth enough that I'm slowly buying my dentist some nice accessories for his boat, as they start to crack and I get crowns put on.
Code hygiene is also important.
Back when I started coding, my teacher (who I am in debt to for being at least 10 years ahead of his time and setting up a real programming curriculum (no, we didn't use abacuses...)) made us write down our programs on paper before we were allowed to use computer time. Not only did you have to write it down, you had to show it to him, and if it wasn't good enough, he'd make you copy it from scratch with the necessary changes.
When I got better, I got introduced to my first text editor. Line oriented, a real improvement. Rather than typing a line over, you could make changes to it.
Then, the fateful day came when I got to use a screen-oriented text editor. You just used the arrow keys, and you could make changes *right in your code*.
Very powerful. And very dangerous, because it supported
COPY AND PASTE
(Cue emphatic and scary music).
Copy and paste is not a sin - it's actually quite a useful thing, but features like it make it far too easy to do bad things. Need a function that's almost like the one you have? Copy and Paste. Need to add another conditional into that double-nested loop? Just insert it in there. Need a class that's almost like what you have? File copy, then search and replace to change the names.
Which leads to too much function complexity and duplication, and to our fifth sin:
Sin #5 - Deferred Refactoring
Once you start deferring refactoring, things get bad. Even if you have good intentions to come back and "clean that up a big", you often don't.
That's why I find agile methods and shared code ownership so interesting. If there are good tests in a codebase, I can find the ugly code that a coworker has written and refactor it into something nicer rather than just trying to get picked to work on "the new codebase"...
Now go brush your teeth, and it wouldn't hurt you to floss sometimes...
I've been reading Good Math, Bad Math for a while now, and it has a fair number of interesting posts on it.
Today I read Why so many languages? Programming languages, Computation, and Math. (a followup to Type Checking in Programming Languages)
As a former semi-professional language designer (involved closely in the C# language design), and develop whose written in a fair number of languages, I think that Mark is missing part of the point.
At a high level, languages have different kinds of abstraction *and* different levels of rigor.
Mark's discussion seems to be about the former point. And it's true that that kind of abstraction means something - functional languages are inherently better at some sorts of problems, and worse at other sorts of problems.
Now, could you design a language that incorporates features of functional languages and procedural languages? A combination of Haskell and C#?
I think you could. Whether it would be coherent and understandable (ie usable) is another matter - I think you could easily end up with an awful mess. And even if you didn't, it could easily be so big conceptually that it would be hard for many developers to get their minds around it. Compactness and simplicity have big benefits as well in programming languages.
Those who have been following the LINQ project may have noticed an obvious parallel - LINQ is precisely about taking two different languages and figuring out how to join them in a rational way. I don't think it's going to be a mess, but whether it adds too much complexity
The second point - which Mark doesn't cover - is one of rigor. Different application spaces require very different levels of rigor. Or, to put it another way, the amount of rigor that it makes sense to pay for is different from application space to application space.
For what professional developers think of as "real projects", rigor - in the form of strong type checking, contracts, things like that - is a very useful thing, as it helps achieve the target quality.
But for what I'll call casual software - which encompasses a really broad range, from scripts to hobby programs to web pages on up to some departmental apps - that amount of rigor isn't required, and sometimes the cost isn't worth it. I could write a short script to launch my profiler and do something with the output in a high-rigor language, but it's probably faster to write it in Perl, or some other scripting languages.
I do a fair amount of carpentry and some woodworking in my spare time. The question "why is there more than one programming language?" is akin to asking "why do you own more than one saw?"
Different tools for different jobs.
The World Cup is once more about to commence.
During the 1998 World Cup in France, we were in Europe, and the Europeans take their football very seriously. Buildings in the Netherlands are covered with the orange. No matter where you are and who is playing, 30 minutes after a match is over you will hear people driving around honking their horns and waving flags (well, that part you see rather than hear) in celebration. And it's common to see the police in riot gear in preparation.
During the time that was there, we watch 30 some games of soccer. Which seems a bit excessive, but it's so rare to see good soccer in the US, and to be able to contrast the attacking style of the Europeans vs the more possession-oriented game of South America.
It can be confusing, however, to watch European TV, especially since the broadcasts were from various countries. In the US, we learn the names of countries, but we don't learn the names in other languages (except, perhaps the home language of the country).
For example, in the US is would be Germany. In Germany, it would be Deutschland. But there's also:
Duitsland (Netherlands)L'Allemagne (French)La Germania (Italy)Alemania (Spain)
So, when you see a three letter code, it may take you a bit of time to figure out who you are really watching. They may use the standard euro codings for country names, but I don't really know those.
And, the US may show up differently. USA (Germany), Etats-Unis (France), Estados Unidos (Spain)
US Television looks pretty good, with HD broadcasts of all 64 games.
Finally, go watch this cool Nike Video...
As you get on in years, you feel the need to pass on your accumulated wisdom to the younger generation, which they will promptly ignore until they're as old as you are, at which point they'll admit that you were right all along and their lives would have been *so* much better if only they'd listened rather than listening to that crappy music of theirs (why oh why can't they have any taste in music?)
So, at the risk of repeating the Miss Manners incident, I hereby present the following list, in no particular order:
Eric's Tips for a Happy Marriage
Why should you listen to me? 7300 days, baby!
Rule #1 of Regex debugging
The regex engine isn't hung. It will finish eventually.
However, "eventually" may not until after the heat death of the universe.
You either didn't anchor your string, or you didn't think clearly about how the quantifiers "*" or "+" work. Or both...
Monday I went on the 7 hills ride.
Wednesday night, I wrote a long and detailed post about it, and hit the "Post" button.
In a fit of editorial brilliance, my blog server chose that exact moment to experience a problem, and the post vanished into the ether.
Few will quarrel that that event was a net positive for western civilization as a whole.
So, here's the short version.
Now, that that's out of the way, there were a few comments on the 6th deadly sin post that I'd like to comment on:
(BobHy) "Inappropriate" is relative to time (as your first story illustrates) and point-of-view ("cui bono"). Would you agree that cleverness which benefits the user who runs the code (efficiency) or the team who maintains it (maintainability) is appropriate? And if the clever bits trade off one of these against the other, who gets to decide the direction?
Inappropriate is obviously a value judgement. Who decides? Well, I do, since it was my post. In general, I'd expect that the team would decide, though in my experience there aren't that many teams with the sort of culture that allows this.
But, yeah, I agree with this.
(BobHy) OTOH, even when we consider cleverness whose only benefit is to amuse its author, it's fair to ask whether the author's happiness is itself a benefit to the user community ("a happy programmer is a cooperative, bug-fixing programmer") or to the team ("a happy programmer remains on the team and trains his/her successor").
An ancient Chinese programmer once said,
I pity the fool who has to maintain or extend the code of a programmer who wrote clever code because it made him happy.
I've experienced many cases where a developer writes code that is clever, moves on to another job, and then the people who have to deal with the code have to deal with that cleverness. My current team is dealing with this now, and it's a big problem for us.
If you want to amuse yourself writing clever code, do it on your own time. But don't make your team deal with it.
(BobHy) I'm beginning to think "inappropriate cleverness" may be a vacuous term. But there certainly is "incorrect" cleverness, where the claimed benefit of the design is refutable.
You are obviously not a long-term reader (assuming, for the sake of argument, that such a person exists) if you find the presence of a vacuous term in a post of *mine* surprising.
The difference between inappropriate and incorrect seems mostly one of semantics. I chose inappropriate because I think it's more of a judgement call, while incorrect implies a black and white choice.
(Tomer) It's funny, I keep running into arguments as to the pros and cons of the sort of "codespace-optimized" loops you mentioned. I'm actually very much for them - they're usually used where the algorithm is very simple (for example, when writing to a frame buffer and adding a stride value to your target pointer) and tend to make the code "look" a lot more elegant.
I will confess to being somewhat of a code aesthete in my earlier days, looking for more compact expressions. I got started in that back when I was writing games in interpreted basic, and the size of your code could have a big impact on how fast your program ran.
Over the years, writing a lot of code and trying to understand other people's code, I realized that the #1 most important feature of well-written code is clarity. And for me, the two most important facets of that are:
The world where for loops just do looping is a conceptual simplification over the world where they sometimes do additional things. In the first case, I read the for statement once, and then concentrate on the loop body. In the second case, I read the for statement, read the loop body, but have to remember that there's something else going on that I have to go back and refer to later. When you write that, you're making me work harder, when you simply could have put "j += stride;" as the last statement in the loop.
That's why foreach is such a useful construct. It's not that you type less. It's that it's conceptually simple - you know that there's no funny business going on, and all you have to worry about is the loop body.
(Shahar) We used to have a dev in a previous company I worked at (circa 2000) who had his own special way of doing HRESULT-COM error checking..
Shahar goes on to detail what the practice was, which I agree is bad, but it's a matter of degree, since all HRESULT handling techniques suck.
Most code is read far more times that it is written. Go read this post by Peter Hallam, one of the C# compiler devs.