Ben's profileNo Brain, No PainPhotosBlogListsMore ![]() | Help |
|
July 28 Better gas mileage with a clean air filter, right? Read on..."Install a new air filter to maximize your gas mileage!!!" I swear I hear that at least a couple of times a week these days. It's on YouTube. Auto parts stores suggest it. Even the government advise you to do it.
But it turns out, they're completely misguided.
I can almost hear you thinking, "The hell you say?!?!?! Of course a clean air filter will help with fuel economy, since it's obvious an engine would have to work harder to draw air through a dirty filter as compared to a clean filter."
Now, there was a time when a new air filter would improve fuel economy. Back in the days of non-feedback carburetors, the amount of gas metered into an engine was dependent on the absolute pressure differential between the carburetor venturi and atmospheric pressure. Anything that would lower the pressure in the venturis--the most obvious example being the choke on top of the carburetor--would case the air fuel mix to go rich very quickly. And a dirty air filter acted identical to a partially closed choke. I don't think it would be unreasonable to see an MPG decrease of 10-20% with a dirty air filter.
But that was a loooong time ago; the last open-loop carburetor car I drove was a 1979 Trans Am. Since the 80's fuel systems have gone to closed-loop, which simply means they continually sample the exhaust gas in order to calculate how much fuel to inject into the engine. The pressure of the air upstream of the throttle no longer affects the amount of fuel metered into the engine.
Ah yes, the throttle--that's the part people always forget about when they're trying to envision their engine struggling to pull air through the dirty air filter. Because if you think it's hard to pull air through a dirty piece of paper, imagine how tough it is to pull air through a solid plate of metal! And the vast majority of the time you're driving down the road, the throttle plates are just partially open--that is what's limiting the amount of air entering the engine, not the dirty air filter.
It turns out it doesn't matter where in the intake tract the restriction happens--throttle, dirty air filter, a narrow piece of intake tubing--they all have an identical effect. Basically, as your air filter gets dirtier, you'll compensate by opening the throttle more. But since the amount of gas metered into an engine is determined by the exhaust, you'll still end up with exactly the same engine power output and identical fuel consumption. Nifty, eh?
Actually, I'd contend that the dirtier your air cleaner gets, your fuel economy will improve! Crazy? Well, a dirty air filter has the same effect as a throttle that doesn't fully open. Think about this: would you get better mileage if you drove around full-throttle all the time? Or if you never opened your throttle more than halfway? This actually explains why people say devices like "the Tornado" improve gas mileage. It's not about swirling the air entering the engine, it's about putting a restriction in the intake tract that effectively prevents the driver from going full throttle.
So, is there any downside to a dirty air filter?
Just one that I can think of: it absolutely, undoubtably reduces full-throttle power.
Anyway, something to think about next time someone tells you that you should change your air filter to maximize your fuel economy. July 02 Software entropy, revisitedDreaming in Code had a great story about Apple's legendary Bill Atkinson and using lines of code (LOC) as a productivity metric. In summary: Bill rewrote a section of the Quickdraw code to be faster and more efficient, but in the rewriting process he reduced the total lines of code by 2,000. So, when he filled out his weekly management form, he entered -2000 as the number of lines of code written. So much for using LOCs to measure productivity!
Obviously Bill's new version was better than his old version. But how do you quantify that objectively? LOCs certainly doesn't work, but as I continued to think about the problem, I kept returning to the concept of software entropy as a potential solution. So here's some continuations on my original thoughts; the concept still isn't fully flushed out yet, but I think I'm making some progress. Consider this:
Now, here comes the heavier stuff:
In other words, if two functions generate identical output for identical inputs, either could be used by a calling program with no change in functionality. Seems intuitive, no?
Given all of these, I propose the following statement:
Therefore, func0() is more efficient that func3(), even though equivalent, entropy-wise.
I think that if you were to apply these principals to Atkinson's revised code, you'd find the efficiency of his new functions objectively higher than that of the original ones.
Certainly, there's still a lot of work to be done--namely, I still need to figure out how to calculate absolute entropy values for an arbitrary function or statement. But I think I'm heading in the right direction.
Ben
May 14 Dreaming in Code and some thoughts on processRecently I've been reading Dreaming in Code, which is billed as "the first true successor to Tracy Kidder's Soul of a New Machine." I really enjoyed Soul of a New Machine, so I figured I couldn't miss with Dreaming in Code.
Both are written in the same style, with a relatively non-technical author watching and writing about a group developing a product; the main difference is that Soul concerns a hardware project (Data General's first 32-bit machine) while Dreaming is about a software project--namely Mitch Kapor's open-source Chandler PIM.
For what it's worth, I enjoyed Soul of a New Machine more than Dreaming in Code. It might be because the former was about hardware development, something I'm not familiar with. But I think more likely it's because at the end of Soul, they actually had a solid, finished computer whereas at the end of Dreaming, they had (at best) a buggy, slow, barely useful piece of software.
Regardless, one positive aspect of Dreaming in Code was that it touched on several topics on which I have strong opinions, so it was a good catalyst for me to revisit how software could be built better. So, hopefully over the next week or so I'll post a few entries giving my take on what was presented in the book.
First up: Software development processes.
What's funny is that I bet if you spoke to most people I've worked with, they'd say, "Oh yeah, Ben, he hates any formal development methodologies!" But that's really not the case at all--conversely, I'm convinced that process is a huge key to building better software faster and cheaper. The problem that I see is that most of the development processes out there tend to do the opposite--they slow down the development cycle while not improving the quality, features, or performance of the software being developed.
Don't believe me? How many times have you heard a discussion about software process where someone says, "we need to make sure that we don't start skipping the process when crunch time comes"? Whenever I hear that, I see a huge red flag going up--why would someone skip the process in order to get something done faster? Wasn't that the purpose of the process in the first place?
For example, Henry Ford brought the concept of the assembly line to auto production in order to improve the speed and consistency of building cars. I can't believe that if the Ford factory was struggling to meet production numbers, the workers would start saying, "wow, this assembly line idea is stupid! I'm just going to start building cars one at a time like we used to, because it's faster." Instead, everyone quickly realized that the assembly line was a far superior way to build cars, and to do anything else would slow them down.
Yet the opposite is the norm in the software world. People are resigned to thinking that all development processes invariably slow down the development cycle, with the benefit of some esoteric payoff at some point in the distant future. This drives me absolutely nuts--a good process should speed up the development process, with obvious payoffs in a relatively short timeframe (days or weeks, not years). Anything else is doomed to fail. April 23 Things that make me chuckle, part IIII can't count the number of people I've encountered who bemoan web service performance, typically attributing the problem to the use of SOAP over HTTP.
Google search results are returned to the user using essentially the same transport mechanism (HTML over HTTP).
Yet I have never run in to anyone saying, "Google searches are so slow! It's all that damn HTML markup overhead and HTTP headers"
Hmm... April 21 WWF... er... IRL at Twin Ring MotegiJust to set the record straight: I am neither a Danica basher, nor a Danica lover. I think she's a very good driver, not as good as the best in the IRL, but certainly much better than guys like AJ Foyt IV, Marty Roth or "Special" Ed. So, to me, it was just a matter of time before a bit of luck on her part and a bit of misfortune for the competition spelled a victory for her. Which seems to be exactly what happened last weekend.
Now, I don't watch the IRL races because I personally believe that a race car should be beautiful to look at and listen to, and the current Dallara is 1) possibly the ugliest open-wheel car ever and 2) sounds like half-ass ARCA wannabe. But during the Long Beach race broadcast, they showed a clip of her pass on Helio.
I couldn't believe it. Helio just moved over and let her through... I mean, no attempt at all to defend his position, he just got out of the way and, judging by how fast she went by him, let off the gas.
Hmm... My personal take is that he wanted to make it absolutely, positively, crystal clear to everyone watching that he let her by.
Then, in an interview with him after the race, my wife picked up on an interesting comment he made: "She won fair and square". Gosh, why would he have to say that? I mean, unless he was concerned that people might think something fishy was going on?
Something did seem a bit fishy to me. That wasn't quite the same Helio I remember on the pole for Hogan Racing at Milwaukee, trying his heart out as the car failed underneath him. Yes, he was low on fuel. But to not make any attempt whatsoever to hold his leading position? Am I watching open-wheel racing or a friendly game of Checkers in the park???
During the Long Beach race, Scott Goodyear commented about Graham Rahal and Danica winning the last two IRL races: "They [the IRL] couldn't have written a better script." No, they couldn't have. And he said "script", not me.
Then I thought back to the race prior to Motegi... Normally I'm not much of a conspiricy guy, but wow, what were the chances that a young, American 2nd generation driver would win in his first race ever in the IRL? Especially with a team with no experience with the Dallaras, heck, not even enough time to paint their car. There's no doubt that Graham's a fantastic driver with a great future, but he wasn't able to win last year (although he came mighty close at times) in a series where Newman/Haas/Lanigan was certainly the class of the field. Now, in a completely different car, against muiltiple first-rate teams with years of experience with the Dallara, he pulls off his first win?
Possible? Obviously. Likely? Not very. Convenient for the IRL? Absoutely!
I mean, what could possibly be better than a win by a young American driver with a famous name, no less from the competing series that just merged into the IRL?
The answer: A win for Danica.
Hey, hey, guess what?
I'm not calling BS quite yet, but I will say this: The absolute next best thing possible for the IRL would be a win by Marco. Then the speedway could bill the next Indy 500 as the battle between the three American young guns, two with famous names and the third the first female to win a major open-wheel race. It has to be mighty, mighty tempting for the IRL: going into Indy, a more perfect scenario couldn't be imaged.
Other than that, perhaps, the ruse is revealed. March 04 Quick catch-upBetween the new job and running the kids around I haven't had much time to post, although there's been lots of things I've wanted to post. So, here's a quick summary:
Ok, gotta run. Toodles! Ben January 16 Just trying to jinx the JettaI'm throwing caution completely into the wind and telling everyone: If I can make it another month, the Jetta will have gone an entire year without a check engine light!!!!!
That's not to say the Jetta has been trouble-free in the last year; rather:
But considering the car has never gone more than 5-6 months before that stupid light came on in the last 5 years, I think I have officially made a breakthrough!!! Of course, it still has to go another month ;-) Ben Why are two musical instruments always louder than one?Yeah, this is another of my "I can't believe he's asking such a dumb question" questions:
Say we have a stringed instrument playing an 440Hz tone (e.g. A over middle C in standard tuning). If another person comes along with another instrument and starts playing a 440Hz tone, the amplitude of the sound always becomes louder. Duh, eh??? :D
But here's what I don't understand: If the 2nd player started playing the 440Hz note exactly 1.137 milliseconds after the first person started playing the note, the sounds waves emanating from the two instruments should be 180 degrees out of phase, cancel each other, and you should hear nothing but silence.
Obviously, this never occurs. Why? Do excited strings naturually fall into phase with one another? Is there something odd with sound waves that prevents this from happening? If so, then how do the Bose noise-cancelling headphones work?
G'luck!
Ben January 12 Ben's 2008 F1 PredicitionsEvery year I make F1 predictions and almost always, the events unfold throughout the year to prove me wrong ;-) Actually, my kids are starting to use my flawed predictions to their advantage; for example, when I pick a line at the grocery store, it's always the one where the people ahead of us have items not in the price database, arguing about the price items ring up as, writing checks without an ID, blah blah blah. So, being brighter than myself, they go into the line I *don't* pick. So far, it's been working pretty well.
Anyway, I think the 2008 season is going to be fantastic, with more twists, turns, and drama than 2007. Here's the main lines I think we'l see:
Seriously, though, I think this will be the best season since the early 90's, and I chalk it all up to Michael Schumacher: I think we're currently seeing the strength of the drivers who grew up during his dominence: Hamilton, Kovalainen, Rosberg and most of all Alonso, who went head to head with Michael--and beat him. They saw his speed, his commitment to win--always. And it raised their game far beyond where they would be, had he not been on the scene. Cheers! Ben January 05 Real-world examples of bad developer habitsThis blog is a lot like the band Spinal Tap: its audience is pretty, umm, "selective." But that's been changing over the last month, as I see a steady stream of visitors who can't get Ventrilo 3.0.x to work and are looking for solutions.
So since it's obvious that lots of people are still having problems with Ventrilo, I went to the Ventrilo web site to see if they had an updated version of the client, or at least some information on what exactly was happening. Instead, I found this explanation of the problem which actually irked me a bit, as they're making some classic developer mistakes that I've seen occur time and time again over the years. Here's some excerpts:
Bad assumption. While this is certainly expected functionality for TCP connections, it's not true for UDP; compare the UDP RFC and TCP RFC for a more detailed explanation. But that's the whole point of UDP: it's a minimal, stateless protocol with doesn't impose any rules as to how to use it. The downside of this is that there's no guarantees as to what a firewall or router will do once they see an outbound UDP packet.
Another bad assumption. Yes, it's very common that by default, SPI routers and firewalls will start listening for incoming UDP packets once they see an outbound packet. But ISA 2006 is an SPI router/firewall, and it doesn't do this by default. And based on the number of people having Ventrilo connectivity issues, ISA 2006 isn't the only exception to this "rule".
This one actually made me cringe a bit, only because I've seen this happen so many times before. Usually it's in the form of the following exchange:
I can't count the number of times I've seen developers dismiss bugs and errors as some bizarre, "one-in-a-million" aberration that in an miraculous Act of God, somehow occurred on the computer down the hall. The truth is that if you're seeing a problem on one or two QA boxes, you're going to see it on many more machines once the code goes into production. What the developer should do is beef up the error handling code in order to pinpoint what's occuring, and then fix the code. For what it's worth, typically when I see this interaction between development and QA, it's a sign of non-robust code. Since I'm a believer in not bringing up a problem unless you have a potential solution, here's what I'd suggest to the Ventrilo development crew:
Looks like a win-win to me, people who can support UDP communications get the advantages that UDP can bring, but if someone's network doesn't support UDP as Ventrilo needs it to, they still get the functionality of the old Ventrilo client. Ben November 29 Using Ventrilo 3.0.x with ISA 2006Most likely if you've upgraded to Ventrilo 3.0.x and you're using ISA 2006 server, you've made the discovery that Vent no longer works. At least that's what happened with my daughter, who uses Vent with her WoW buddies.
For starters I went to the forum on the Vent site to find out lots of other people are having problems with the 3.0.x release of Ventrilo, but what sucked was there were many posts about problems, but barely any posts with solutions. By the time I hit the forum I had sifted through the ISA logs and realized that Ventrilo switched from using TCP connections to UDP connections, so I put up a post asking if there was some way I could configure the software to use TCP connections again. Someone, no doubt trying to be helpful replied, "Enable UDP". Ah yeah, of course--now I just need to find the magic checkbox for enabling UDP. Hmm, can't seem to find it.
So, with a bit more investigating in the ISA logs and some packet sniffing with Wireshark on the client machine, I ended up with a reasonably good idea how Ventrilo 3.0.x connects to the server. Here's what I found:
Armed with this data, you'll need to create a new protocol in ISA 2006 with the following settings:
Obviously, if you're connecting to a Ventrilo server on a port other than 4000, you'll have to use the port you're using instead of 4000. The UDP connection on port 5000 and 6100, though, won't change regardless what server port you're connecting to. Also, the UDP connection must be specified as "Send Receive", otherwise ISA 2006 will just discard the UDP packets inbound from the server. Port 5000 could feasibly left as just "Send" since the return packet doesn't appear crucial to the client, but I don't really see the advantage of that. However, you might not be out of the woods quite yet: if ISA 2006 already has a protocol set up for UDP packets going to the port you're connecting to on the server, then ISA will use that protocol instead of the one you've just defined. In my case, a legacy ICQ protocol is already defined in ISA 2006 for UDP packets going to port 4000. And, since this protocol defined the port 4000 UDP connection as "Send" and not "Send Recieve", returning UDP packets were being tossed out. The solution for this is to either create a deny rule for the offending protocol, or un-include the protocol from a blanket rule that would normally allow any traffic originating from the Internal network going to the External network. I used the latter. I'm not sure how many folks are using Vent on a network with ISA 2006, but I hope this helps someone! ;) Ben November 03 The Jetta 120k challenge!Last weekend, with the mileage on the Jetta hovering dangerously close to the 60k mile powertrain warranty, I replaced the timing belt, water pump, tensioner and a couple other minor things. I figured with my luck, I'd hit 60,001 miles and *snap* the timing belt would break, leaving me with a $2k repair bill. So, I figured I'd do some preventative maintenance before the bell tolled.
First off, have to give props to www.dieselgeek.com, bought their "all-inclusive" timing belt kit and it was indeed all-inclusive. All the parts were first-rate, the price is great, and packaging/shipping speed was commendable. Good stuff.
One thing I was actually looking forward to while changing the timing belt on the Jetta was that the crank pulley was attached with 4 allen key bolts, instead of a big bolt on the end of the crankshaft that's torqued to some ridiculous spec like 144 ft/lbs. What the heck???? HELLO!!!! The pulley is driving a few accessories, not holding a house together... On the cars I've previously done timing belts on ('85 Camry (x2), the Sebring, and I know I did a Ford 2.3L 4-banger, just don't remember it) I've taken the ghetto approach of putting a breaker bar on the bolt, jamming it against the frame or a driveshaft, and hitting the starter to break the bolt free. I always hated doing that, but... it works.
So, the good news was that the crank pulley came off without drama. Unfortunately, that was the only high point of the procedure. The rest was typical timing-belt changing drudgery, just in a smaller-than-anticipated space.
Prior to doing this work I had checked out a walk-through on VWVortex, which convinced me it was pretty much a typical timing belt change. One thing I found interesting was that people were complaining that they couldn't get the lower section of the motor mount out. Of course, I figured that no doubt these people were (relatively) clueless, and given my experience getting the Bose amps out of the doors in the Corvette, I'd have no problem getting the lower motor mount out. Also, I wasn't sure why they were using the TDC mark on the flywheel, because *certainly* this would be marked somewhere on the crank gear, right?
Yeah, right. ;-)
It turns out that the motor mount hangs up on the tensioner assembly, so you pretty much have to leave it hanging in place why you work around it. And if there's a TDC mark on the crank gear, I certainly couldn't find it! Score 1 for VWVortex, 0 for me :-s
A couple of things I found notable. First, I was very surprised that when I pulled out my water pump, a chunk of the impeller was missing. This was something also mentioned on VWVortex, which I assumed was due to the impeller getting bumped against the block while the water pump was being removed. But I was pretty careful while removing the water pump, and nonetheless the impeller was broken. Hmmmm.... It doesn't seem very logical that the water pump was working fine with part of the impeller missing, but hmmmm....
The other notable part was that there was no adjustment to preload the timing belt before the tensioner was released, as there was on the Sebring. The net result of this was that even with the tensioner fully retracted, the timing belt was still tight enough that you just couldn't slip it on the pulleys. Or, I should say, I sure as heck couldn't figure out how to just slip it on, even after a couple hours of trying different approaches. In the end (and I hated doing this), I got the belt partially on the crank gear and then started turning over the engine with a wrench until the belt worked its way fully onto the crank gear.
Anyway, everything's back together now so I was thinking to myself, "What's the chance that I won't have a check engine light before the next time I have to change the timing belt (at 120k miles)?
It could happen. It *might* happen. But will it???
I know it won't. But hey, I can dream, right?
Ben October 22 Blackmore's Night at House of BluesI was a big Rainbow fan in high school but never saw them live, so when I heard that Blackmore's Night was coming to Chicago I figured I'd better take the opportunity to see Ritchie live at least once in my life.
If you're not familiar with Blackmore's Night, it's a Renaissance music band formed by Blackmore in 1997 and fronted by his 25-year-younger fiance, Candice Night. Yeah, I know. When I first heard about the project I said to myself, "You've got to be kidding..." While I knew of their existance and checked out their web page a couple times a year, I never bought any of their albums, mainly because I'm not a huge Renaissance music fan. I enjoy most classical music, but I find Renaissance music to be a bit *too* formulamatic--kind of like taking Baroque music forms and simplifying them another order of magnitude.
Regardless, Blackmore was going to be in Chicago, and I wasn't about to miss it. Hell, I would have gone even if he was just playing spoons.
I really like House of Blues, too. While I find the whole HOB thing a bit too commercial, at least in Chicago they've got a decent sound system with a competent crew, and the size of venue is ideal. They were pretty full for the show; not quite packed like sardines, but more people than for any other show I've seen at HOB (although I've only seen a couple other acts there).
While they were setting up, I noticed the guitar tech putting a white Strat into one of the guitar stands. I have to admit, just the sight of that got the hair on my neck standing up. Hmmm, maybe they'd crank out a 20-minute version of "Catch the Rainbow"? Hey, I could hope!
It turns out that their music isn't traditional Renaissance music, but rather Renaissance-influenced rock songs. Take the direction Rainbow was heading in the 80's and throw in some Renaissance musical elements and lyrical themes and you'll have a pretty close idea what their music sounds like.
I was pleasantly surprised to see that Candice was an excellent singer and a great frontman (frontwoman???). Great tone and vibrato and no problems hitting notes. If anything her range was a bit limited, but I'm not sure if that was her or just the music. Overall, though, I was impressed.
The rest of the band was top-notch, which really was no surprise--Ritchie always had excellent players (and a hell of a lot of them!!!) throughout the history of Rainbow.
My favorite parts were the 3 songs he played on the Strat, they were much more straight-up rock n' roll and more to my liking. He even did an extended solo in one of the songs, nowhere near as long as the old Rainbow 15-minute solos, but he got a couple of minutes in.
One of the things I love about music is that you can still play it well into your 70's--witness Segovia or Alicia de Larrocha as a couple of examples. At 62, I thought Blackmore was playing better than ever. I have to give Blackmore credit, too--rather than just resting on his laurels and cranking out "Smoke on the Water" forever, instead he's pushing the musical boundaries a bit with his vision of Renaissance rock. While I'm sure there are others doing similar stuff, it's certainly something that isn't heard often.
Two other things also impressed me--first, the tone he got out of his Start. It wasn't the thin single-coil sound you usually expect with Strats, but it wasn't the traditional humbucker sound--rather it was a compressed sound that sounded... well, great.
The other thing was that I had never noticed in his playing previously was a similarity to Jeff Beck in that he didn't just *play* the guitar, rather he sounds like he's ripping the notes out of the guitar. Yeah, I realize it's a bad description, but I think Jeff Beck fans understand what I'm getting at.
In summary--very glad I saw them, and would certainly pay to see them again.
Ben October 15 Evil monolithic systems: Cause #1Although there's dozens of things that contribute to the creation of evil monolithic systems (spaghetti code, bad application of patterns), there's two main design elements that I find to cause the greatest pain. Unfortunately, they're also really prevalent design concepts, so... the list of people who think I'm completely nuts or stupid might get incremented by a few. All I ask is that you think about it a bit and ask yourself if you've run into the same issues in your experience before writing me off :)
With that disclaimer, here's evil monolithic system cause #1:
Using SQL databases to share data between applications
As I've stated before, I really love SQL databases: they're incredibly fast and powerful. And because they're so easy to use and efficient, it's very common to use them for inter-application communication. I can't count the number of systems I've encountered where there's dozens of applications that all access the same database.
But here's the problem: there's probably hundreds or thousands of SQL queries embedded within all these programs. And all these queries are tied intimately to the database for a few reasons:
First, SQL joins are completely dependent on the schema: if any of the relationships in the database change, every single query that references that relationship will have to change.
Second, most SQL data access in programs is tightly bound to the data type. So even though the SQL language itself is pretty datatype-agnostic, the programs themselves like explicitly reference the type. In other words, although the following SQL query is valid regardless of the datatype of the OrderNumber column
most likely the code actually reading the data is similar to this:
And that code will fail if, say, you need to change the type of the column from a number to a character string.
Third, SQL tends to get placed anywhere and everywhere. Some programs may have a data layer, others do not. Perhaps that program does all its data access through stored procedures. Or maybe there's some jobs running on the server. Or DTS packages. It's rarely an easy job determining all the places that a table is accessed.
The end result of all of this is that you end up locked to your existing database schema. And as requirements or performance dynamics change, you're stuck--either you have to say, "No, that's not how the database is set up" or perhaps you'll come up with some gargantuan estimate for how long it will take to modify all the code that needs to be changed.
In either case, it's a situation you should strive not to get into in the first place.
Ben October 12 Evil monolithic systems: What they are and why they're badSo what exactly is an "evil monolithic system?"
Well, "system" is easy--a collection of applications that, working together, complete a process. It could be any process; for example, an order entry and fulfillment system, or an engineering system that collects data, crunches numbers, and spits out reports. The key is that it's multiple applications which work together.
If the applications that comprise the system are overly coupled, though, you end up with what I like to call a "monolith"--because no one application can be changed without affecting the other applications. In other words, even though the system appears to be modular because it's split into several applications, in reality it's no different than having one huge application.
Here's a couple scenarios which are giveaways that you're dealing with a monolithic systems:
And that's where the "evil" part comes in--because monolihic systems are overly coupled, you can't efficiently change them to deal with changing requirements. Not only that, they tend to be fragile because it's easy for a legit bug fix in one applications to create a subtle, hard-to-find bug in another application within the system. The bottom line is that monolithic systems are bad, and something you want to avoid. Next up: the main causes of monolithic systems. Ben September 24 Things that make me chuckle, part IILast week a colleague of mine pointed me to SharpDevelop, which is a free .Net IDE. Personally I wasn't too interested in it since Visual Studio 2005 works just fine for me, but nonetheless I dug around the site a bit more unitl I stumbled into something that piqued my curiousity more than a little: the SharpDevelop C# Coding Style Guide 0.3. Normally, I take coding guidelines with a grain of salt; usually they turn out to be egotistical exercises in proclaiming how much better the world would be, if only everyone else made their code look just like mine!
This document, though, seemed different from the typical coding guidelines. It announced it could "...be read as a guide to writing robust and reliable programs."
That last line resonated within me, since I've spent the last decade tinkering with different approaches to improve robustness and reduce defects in software. I started to download the file, with my curiousity building: had they come up with new way to simplify state management? Perhaps a new, novel approach to exception management? Maybe something I had never considered before?
Hahahahaha! Yeah, right. It was just another document with the same old junk about what line your curly braces should be on, where you should use Pascal casing vs. camel casing, blah, blah, blah.
Don't get me wrong, it's nice when code looks consistent, and it's something to strive for. But do people really fool themself into thinking that a program will be more reliable and robust because of whether they start their variable name with an uppercase versus lowercase letter?
When was the last time you were debugging a program and said, "Oh, I see the problem! I should have put another blank line between those two statements!"
Yeah. Me either.
Ben September 22 Why don't American car companies want to sell a car to me?While I'm not currently in the market for a new car, I'm always keeping an eye open as to what's currently available, in case the Jetta develops some major malfunction and I decide to cut my losses by just dumping it. But, before I consider a car, it has to meet my basic feature list that I've been using since 2000 or thereabouts:
When I was buying my last car in 2003, the car that came closest to my list was probably the Nissan SE-R Spec V, which missed out on the independent suspension and seat heaters. The other two cars I seriously considered were the Jetta (missing out on the 6-speed and independent suspension, but pretty close to the $20k price limit) and the Subaru WRX (missing the 6-speed and seat heaters, and really too far from $20k for serious consideration). In the end I picked the Jetta over the Nissan because the Jetta came across more as "premium" small car while the Nissan seemed more like a cheap car with an uprated suspension and engine. Four and a half years later, I still feel the same--I think I would have been disappointed with the low-cost feel of the Nissan, although I'm certain it would have been much more reliable with the Jetta. These days, I think the car that most closely matches my criteria is the Mazdaspeed 3. It's not under $20k, but it's reasonable close (and I realize that $20k is pretty unrealistic for a car these days) and it's as quick as our Corvette. So how does this all relate to American car companies? Simple: As you've probably noticed, I haven't mentioned a single American car that's come close to my new car criteria. And that bugs me, because I really want to buy an American car. I'd much rather buy an American car than a foreign one, but nothing they offer was close enough to my requirements to merit consideration. The biggest problem for me is that the American car companies offer very few cars with manual transmissions. I'd often say, "Cavaliers and Corvettes"--those were the only two Chevrolet cars offered with manual transmissions; everything else was strictly automatic. In 2003, probably the closest American car to my criteria was the Dodge Stratus R/T, but the MSRP on that was like $27k. I think the final price on that Stratus would have been close to the $21.5k I spent on the Jetta, but even thinking about trying to get a car salesman down from $27k makes me feel ill--the endless "let me run this past my manager" smoke breaks, the "I'm losing money on this deal" BS, the constant pushing of unwanted paint treatments. I think that at the time, American car companies were trying to make customers feel like they got an expensive car for an incredible discount. But it backfired for customers like me, because I never stepped into a Dodge dealership since I didn't want to deal with hours of salesman BS while they whittled down the price $200 at a time. Dodge, are you listening? Do you care? I'm not sure why the American car companies don't want to build a car that I'd consider buying. Certainly I'm in a vast minority since I prefer a manual transmission. But the German and Japanese manufacturers have no problems offering a variety of cars to me with manual transmissions. Why don't the American manufacturers? I guess it's because the sales volume of manual tranmission cars would be low enough that they can justify losing that business. Oh, well. Perhaps someday they'll building something that comes close enough to my list that I'd consider buying. I'm not holding my breath, though. Ben September 19 Why I dislike object-relational mapping, Part IIHere's another reason I'm not a fan of object-relational mapping fan:
It doesn't leverage the strengths of SQL database servers
I'm continually blown away by the performance levels of modern SQL database servers, whether it's Oracle, SQL Server, DB2, even MySQL. It always amazes me how you can join multiple 50 million row tables, filter and sum the results, and if it takes over a couple hundred milliseconds you immediately think, "Hmmm, l bet we don't have the proper indexes". The progress database developers have made with query optimizers over the last 30 years is just phenomenal, at least in my opinion.
Fans of object-relational mapping, though, are less interested in what a database server can do, and instead are only interested in how the database can provide object persistence. What's more, the traditional one-object-to-one-table paradigm pretty much tosses out a bunch of SQL concepts such as joins and aggregate functions. Rather, SQL queries tend to be simplistic, such as "SELECT OrderNumber, OrderDate, this_field, that_field, etc FROM Order WHERE OrderID = 12345". Then a small chunck of code takes the data returned from the query and plops it in the object's attributes.
But ignoring SQL database functionality like this is a major mistake in my opinion. Let's look at a simple example, based on an the order and its associated attributes from my previous post on object-relational mapping:
A user comes to you with a practical request: they want an item on their dashboard screen that displays the total value of "rush" orders currently being processed. This would give them a quick way to determine if any exceptional orders were being processed that necessitated special care; in other words, if you've currently processing a few $100 rush orders, you'd be confident that your fulfillment process will handle them fine, but if you see $5,000,000 in rush orders, you might want to personally monitor the fulfillment process there's a high risk associated with filling these orders.
First, here's my rough object-relational implementation. I'm sure I could probably streamline it more, but I think anyone who's familiar with object-relational mapping would recognize the basic gist:
class Order
{ public int OrderID; public string OrderNumber; public OrderLine[] OrderLines; public OrderAttribute[] OrderAttributes; } class OrderDataLayer { public static Order RetrieveOrderByOrderID(int orderID) { Order result = null; SqlConnection connection = new SqlConnection(); connection.Open(); string sql = "SELECT OrderID, OrderNumber FROM Order WHERE OrderID = " + orderID.ToString(); SqlCommand cmd = new SqlCommand(sql, connection); SqlDataReader reader = cmd.ExecuteReader(); if (reader.Read()) { result = new Order(); result.OrderID = Convert.ToInt32(reader["OrderID"]);
result.OrderNumber = Convert.ToString(reader["OrderNumber"]); result.OrderAttributes = OrderAttributeDataLayer.GetOrderAttributesForOrderID(orderID);
result.OrderLines = OrderLineDataLayer.GetOrderLinesForOrderID(orderID); } reader.Close();
connection.Close(); return orderID;
} public static Order[] GetRushOrders()
{ Order result = null; SqlConnection connection = new SqlConnection();
connection.Open(); string sql = "SELECT OrderID FROM OrderAttribute oa JOIN Attribute a ON oa.AttributeID = a.AttributeID WHERE a.AttributeName = 'rush'";
SqlCommand cmd = new SqlCommand(sql, connection);
SqlDataReader reader = cmd.ExecuteReader(); List<Order> tempList = new List<Order>();
while (reader.Read())
tempList.Add(RetrieveOrderByOrderID(Convert.ToInt32(reader[0]))); reader.Close();
connection.Close(); return tempList.ToArray();
}
} class OrderLine
{ public int OrderID; public int ProductID; public int Quantity; public double UnitPrice; } class OrderLineDataLayer { public static OrderLine[] GetOrderLinesForOrderID(int orderID) { SqlConnection connection = new SqlConnection(); connection.Open(); string sql = "SELECT OrderID, ProductID, Quantity, UnitPrice FROM OrderLine WHERE OrderID = " + orderID.ToString();
SqlCommand cmd = new SqlCommand(sql, connection);
SqlDataReader reader = cmd.ExecuteReader(); List<OrderLine> tempList = new List<OrderLine>();
while (reader.Read())
{ OrderLine orderLine = new OrderLine(); orderLine.OrderID = Convert.ToInt32(reader["OrderID"]);
orderLine.ProductID = Convert.ToInt32(reader["ProductID"]); orderLine.Quantity = Convert.ToInt32(reader["Quantity"]); orderLine.UnitPrice = Convert.ToDouble(reader["UnitPrice"]); tempList.Add(orderLine);
} reader.Close();
connection.Close(); return tempList.ToArray();
} } class OrderAttribute
string sql = "SELECT OrderID, AttributeID FROM OrderAttribute WHERE OrderID = " + orderID.ToString(); SqlCommand cmd = new SqlCommand(sql, connection); List<OrderAttribute> tempList = new List<OrderAttribute>(); while (reader.Read()) orderAttribute.OrderID = Convert.ToInt32(reader["OrderID"]); tempList.Add(orderAttribute); reader.Close(); return tempList.ToArray(); And finally, the code to display the total of all rush orders:
Now let's try that again, ignoring all the object-relational mapping stuff and just using the SQL SUM() function
Now, ask yourself the following:
Finally, ask yourself this: Which is the better approach? Ben September 18 Summer wrap-upJust got my Jetta back from the dealer for the latest recall, this one related to a faulty brake light switch. It wasn't too big a deal for me, since I don't have an automatic and therefore I wasn't stuck like some poor soul in a parking lot with the transmission refusing to come out of Park. But I had noticed on a few occasions that the brake light would stay on after the brake pedal was released, with a particularly funny episode occuring when I was walking away from the car in a parking lot, only to notice the brake lights were still on!
So we're now at the 11th non-scheduled maintenance item in 58,515 miles; one item every 5,320 miles. What's worse is that the rate is increasing: since January 1st there's already been three problems, and we're just into the 9th month of the year--something breaking every three months, instead of the usual five. I'm such a sucker for punishment. And to think the service advisor told me, "the car looks great for 50k miles, you really take good care of this car." Yeah, I do... but it repays me by breaking even more frequently.
To put things in perspective, if you took EVERY other car I've driven in the past 23 years and summed up all times those cars had to go to the shop, the grand total would be less than the Jetta in four years.
But it turns out that's just strengthening my resolve--at first I was determined to get 120k miles out of this car, but now I'll be damned if I don't get 180k. By that time it'll probably be in the shop 6 days out of every week :-p I WILL PREVAIL!!!!
Then I'm gonna drive the damn thing off a cliff.
In other news, I did fix the air conditioner. My first thought was that perhaps the thermostat had broke, but I stood by the compressor unit outside while someone turned on the air inside--and I heard the distinct click of a relay. Hmm, seems like the thermostat was working. So I dug around the internet a bit and came to the conclusion that the fan/compressor run capacitor was bad. Since I don't have a tester that can test capacitors that large, I just decided to replace it since a new capacitor was only $30.
So I put in the new capacitor, turn on that air conditioning, and... still nothing. Grrr....
Next, I check what I should have checked first (this is a constant motif in my life): make sure the compressor unit is getting power. Of course, it wasn't. So then I open up the circuit breaker panel, hmm, everything looks ok... oh wait... why's that one wire look all burnt?
Somehow the circuit breaker for the air conditioning compressor shorted internally, and melted half of the switch--I'll have to put up some pictures, I can't believe the house didn't burn down. So $62 (!!!!) later I have a new circuit breaker, and the air conditioning starts working again!
Let's see, what else. The sewer pipe that was dug up about 8 years ago had to be dug up and replaced, AGAIN. There goes $2.2k down the drain (get it? down the drain? Perhaps I shouldn't quit my day job quite yet???). You know how everyone used to talk about DINKs? I always joke that we're SILK: Single Income, Lots of Kids. It's brutal in this day and age.
I also change the Corvette diff fluid a couple of weekends ago, not too bad of a job at all. I went with Mobil 1 gear lube and a single bottle of GM limited-slip additive, and so far everything's working great.
Actually it's been a real low mileage year for the 'Vette, we haven't even put 1k miles on the car this summer. I had been purposely keeping the mileage low this summer, as I planned to take the car up to the U.P. for our annual trip, but in the end we needed more space and it stayed home in the garage. Oh well, there's always next year!
Toodles!
Ben September 17 Why I dislike object-relational mapping, part I.I've been meaning to write some of my thoughts on object-relational mapping for months now, but I kept running into a problem: there's so many reasons I think it's a bad idea that I could never come up with a coherent post that covered the main points I wanted to make.
Come to think of it, I'm not sure how many of my posts could be considered coherent, but that's a whole different matter :-p
Anyway, I decided to break up the huge object-relational post into several posts, each focusing on a specific problem I've seen. So, let's go!
Object-Relational mapping problem #1: It compromises your object model
Let's take a pretty simple and common example: say I have an object (class, struct, whatever) representing an order object that will be stored as a row in the Order table of a relational database. Also, there's an Attribute table in the database of order attributes that can be assigned to an order, e.g. "rush order", "ship together", things of that sort. I'd like to program this as straightforward as possible, something on the order of this:
But there's a problem--since this is a many-to-many relationship, we have to implement that relationship in a relational database as an intermediate table. So the database will look something like this:
Now, since one of the tenants of object-relation mapping is that each class maps to a table in the database and vice-versa, that means we need to introduce another class in our code:
and I will also need to change the Order object:
Not a big change, right? Well, no, not huge, but it did introduce a few small complicaitons:
First, it's making our code less resemble the problem domain; end-users deal with orders and attributes assigned to those orders, not some OrderAttribute concept stuck in the middle--that's just an implementation necessity. We should always strive to make the structure of our programs match the reality of the problem they're designed to solve as close as possible.
Second, it's adding code to the project without bringing additional functionality. A little red flag should always go up in your head whenever you're writing additional code which doesn't directly help solve the problem at hand. Often, you can't avoid code like this as it's required for housekeeping or the like. But you should always ask the question, "do I really need this code?"
Third, it complicates any code that uses this object, as it now has to deal with dereferencing the intermediate object. For example, you'll have to write
instead of the more clear and conside code you'd rather write:
Certainly, none of these are deal-breakers that would cause your program to fail. But even a medium-sized program will have perhaps a dozen instances of structures such as these, with larger programs having hundreds to thousands. And each instance makes the program a little bit harder to build and a little bit harder to maintain. It's not a question of whether this will work or not, as there are thousands of working, functional programs out there that use these object-relational mapping strategies..
Rather, the question is this: Could they have been better?
I'm sure some people reading this are thinking, "Well Ben, regardless of anything you still have to implement this in the database with the three tables you described, and somewhere you'll have to deal with that complexity somewhere else in your code." Yup, absolutely true.
My solution to this would be to place that complexity in the code that is responsible for saving the order data (and the attribute linkage) to the database, e.g. a Save() method in the order class. Although I'm a self-professed object-oriented heretic, there are certain concepts that I consider extremely valuable, such as encapsulation. In my solution, the complexity of dealing with the intermediate database table is encapsulated into the order object save code. To me, the traditional object-relational mapping approach is just the opposite, needlessly forcing inplementation complexity on the consumers of the object.
Ben |
|
|