If you're going to be in Austin on May 5th and you're interested in some free dev training, I heartily encourage you to attend the Austin Code Camp, a community event hosted by the Austin .NET User Group. Not only is it a great event, but I encourage you to attend because I'm one of the speakers and I don't want the only attendees for my session to be hobos looking for free air conditioning.
What will I talk about? Why, I have a summary for that!
Functional Programming in C# - Ruby, Python, and the resurgence of Lisp have all shown an intriguing alternative to the way most of us program. Typically, we have some data, and we run the data through an ordered set of procedures in a specific order; any deviation from this and things start to blow up. What these other languages offer is the ability to program functionally; that is, the ability to chain together functions without this explicit order and without creating any side effects. This makes it much easier to optimize, verify, and parallelize a program. C# does include the ability to write code functionally, and in this session, we'll explore how to do this, why we'd want this, and a few choice comebacks to use when Lispers make fun of our language.
I know, I know: with a description like that, the assembled crowd will likely constitute a fire hazard. Anyway, I think it's an interesting, relevant topic, and I should have some good brain food for the attendees. If not, well, there's the free air conditioning.
Woah, it's been a while since I updated here. For what it's worth, I blame it all on professional upheaval and sunspots (probably a .5/.5 distribution). To dive back in, I've decided to write a little about what I'm doing right now and what I'm learning from it.
Right now, my employer runs a large sensor network. There's data coming in from all over North America in a variety of ways (satellite, analog cell, digital cell, passenger pigeon), and it's our job to decode all of these proprietary formats and make sense of the data. That sounds kind of cool, and it is. However, the volume and nature of the data impose some constraints on us. One constraint is that, if we ever have a problem with an internal machine or service, we don't have time to discover what went wrong or why it went wrong; we need to get back online in chop-chop, mush-mush fashion.
As a result of that, we have critical services spread over a bunch of machines. If something goes wrong, the main course of action is to reboot this long string of machines in very precise order. (I'll leave it your imagination to determine how well that'd work in a worst case scenario.) My job right now is to consolidate all of these services onto one or two machines, and eventually to redesign/rewrite all of them. It's not quite as fun a job as professional hamburger taster, but it pays the bills and it's giving me the opportunity to learn some interesting stuff.
Now, based on the lessons of the past few weeks, I present an ordered list of things I've learned in trying to maintain and consolidate these services!
1. It's a lot harder to be rigorous in a maintenance scenario. If you're working with a fresh codebase, how difficult is it to write unit tests and implement patterns? Hopefully, you're starting with that mindset, but even if you're not, it's a snap. However, when you inherit a giant, unseemly, Jabba-the-Hut-like heap of code, it becomes a nightmare; there's so much accumulated cruft, it's hard to know where to start. In fact, it's tempting to just add a little more to the Jabba pile yourself.
2. However, you get the better return on your effort writing tests for maintenance code. New code is less likely to be deployed and to be depended upon. As a result, if it doesn't work that well, it's not a huge loss. However, your company does depend on the skeezy maintenance code you're looking at; if they didn't, you wouldn't be looking at it.
3. Resist the urge to point fingers. No matter how crappy the code looks, keep in mind that three years from now, someone will be maintaining your latest whiz-bang design. They won't be saying, "Someone give me this dude's phone number, I must shower him with the candy of his choice!" They'll be saying, "With skills like these, how in the hell did this guy master potty-training?"
4. As weird as it looks, there may be a reason for it. If you're ever looking at a dependable old piece of code and notice 183 nested if statements, entertain the idea that they might be there for a reason. If the code works, look at it, don't rip it out.
5. Watch out for old documentation. Just because your pile of ancient crud comes with some docs doesn't mean you should read those docs. Five years ago, gas was $1.25, people listened to Creed, and your documentation reflected your app. Things might've changed since.
And I've winded myself. Perhaps more will come later.
Remember last entry where I was talking about depth-first vs. breadth-first searching when trying to find the best chess move? Well, that particular tickled my organic memory banks, and I soon remembered that there's a section of Godel, Escher, Bach that expands and elucidates this topic. Computer, begin expansion and elucidation!
A classic example of a recursive procedure with parameters is one for choosing the "best" move in chess. The best move would seem to be the one which leaves your opponent in the toughest situation. Therefore, a test for goodness of a move is simply this: pretend you've made the move, and now evaluate the board from the point of view of your opponent. But how does your opponent evaluate the position? Well, he looks for his best move. That is, he mentally runs through all possible moves and evaluates them from what he thinks is your point of view, hoping they will look bad to you. But notice that we have now defined "best move" recursively, simply using the maxim that what is best for one side is worst for the other. The recursive procedure which looks for the best move operates by trying a move, and then calling on itself in the role of opponent! As such, it tries another move, and calls on itself in the role of its opponent's opponent---that is, itself.This recursion can go several levels deep---but it's got to bottom out somewhere! How do you evaluate a board position without looking ahead? There are a number of useful criteria for this purpose, such as simply the number of pieces on each side, the number of types of pieces under attack, the control of the center, and so on. By using this kind of evaluation at the bottom, the recursive move-generator can pop back upwards and give an evaluation at the top level of each different move. One of the parameters in the self-calling, then, must tell how many moves to look ahead. The outer-most call on the procedure will use some externally set value for this parameter. Thereafter, each time the procedure recursively calls itself, it must decrease this look-ahead parameter by 1. That way, when they parameter reaches zero, the procedure will follow the alternate pathway---the non-recursive evaluation.
- Hofstadter, p. 150-151
It goes without saying that if you haven't read GEB, we probably can't be friends.
One point that's not in that selection is how, while there are useful criteria for evaluating a board position without looking ahead, each specific criterion isn't that useful. That is to say, only a stupid chess program would select a move based solely on the number of pieces on each side. (I say that because, going only by that metric, 4 pawns + 1 king implies a stronger position than 1 rook + 1 queen + 1 king. I am a chess moron and even I wouldn't take that trade.)
The reason I've been on a chess tangent lately is because, for a while, I was working on a chess program. The part that Hofstadter's discussing here, weighing the strength of a potential move, is the part where I had a lot of trouble. Each metric he lists (number of pieces, pieces under attack, control of the center) is useful, but depending on how the application weighs each one (and several others), it gets very different optimal moves. If anyone has any good resources on weighing these factors when calculating the strength of a move, please let me know. (Also let me know if you have good resources on free money.)
For reasons I can't exactly recall, someone asked me the other day about the differences between breadth-first vs. depth-first search. I provided a decent answer, and since this is the ideal place for such dorky discussions, I have elected to throw it up here. Computer, throw up search discussion!
First and foremost, a breadth-first search isn't what you do when you're in a bakery and you're looking for some rye. (That was the dumbest thing I've ever typed.)
Imagine you're looking at a tree structure. A depth-first search would start at the root and descend down a single path of lineage until it reached a childless node at the bottom; then it'd start on the next line of lineage and work its way down again, and so forth until we're out of nodes. A breadth-first search, meanwhile, would start at the root (level r), descend a level (level r+1), examine all nodes at that level, and would then repeat that action at the next level (level r+2). You could find a similar description in a textbook, so maybe that's not so helpful. Perhaps yo-yo vs. typewriter analogy is more fitting? No, I think not. Let's try again.
Imagine you're looking at a chess board, and you're trying to determine the best opening move you could make. You could do this two different ways.
The first way would be to concentrate on a single pawn. You think to yourself, "I could move THIS pawn two spots forward." Then you think what your opponent may do in response. You think, "He could move THAT pawn one spot forward." Then you think to yourself, "With THIS pawn here and THAT pawn there, I could move my bishop diagonally 3 spots." You're looking at a single possible sequence in great depth. That's a depth-first search.
The second way would be to look at the board and examine every possible first move. You realize you could move any of your pawns, or you could move any of your knights. Then what happens? Well, your opponent could move one of his pawns or one of his knights. Then what happens? Well, you could move your pawns some more, make your rooks dance, unleash your queen, etc. Instead of looking at a single sequence, you're looking at each possible move, one level at a time. That's a breadth-first search.
If you had to implement something that could advise you on chess moves, what would you pick? Clearly, the number of potential moves explodes combinatorically as we get deeper into the game. Just as clearly, humans aren't immortal, so we'd need a definitive answer before the heat death of the universe. Since we don't have time to examine each chain of possibilities and breadth-first is the only way to examine each path equally, I'd use breadth-first search. Of course, this may explain why I'm such a crappy chess player.
Last time, I mentioned that I'd been doing a veritable wheelbarrow-load of requirements over the past few months and that I'd come up with a theory on requirements. My starting point was that a requirement is like a hypothesis. I'd like to elaborate on that a bit this evening. Then, if there's time, punch and coookies will be served.
In science, the critical component of a hypothesis is falsifiability. The idea is, a hypothesis isn't valid if you can't disprove it. This applies to all hypotheses, from the big bang to quantum mechanics. (Sidenote: it's the lack of falsifiability in Intelligent Design that makes so many people mad about the theory being taught in science classes.)
Keeping with this idea, if a requirement is a hypothesis, we have to be able to disprove it. For me, this means I must write my requirements as directly and objectively as possible. Instead of writing, "Clicking this button brings up a listbox-sorta thing that's quite visually pleasing," I shoot for "Clicking this button brings up a listbox that supports multi-selection." If a requirement is a hypothesis, you've got to be able to look at the code in action and say, with certainty, that the code supports or refutes the requirement. Fortunately, there are methods in place that make this validation a snap.
How do you falsify a hypothesis? Well, if you're a scientist, you do it with an experiment and empirical data. To me, this is exactly what a unit test provides. Once your requirement has been defined and coded against, you should be able to test for it. Based soley on the requirements, I'd write a unit test that encompasses all conditions for the requirement. If the test passes, we've validated the requirements. If the test fails, it's time to examine what just went wrong.
It's subtle, but I found that if I write requirements with the idea of basing unit tests on them later, I write with more clarity. Knowing what I have to do later, the requirement details the exact conditions for validation. Essentially, it's my unit test in verbose form, and falsifiability is the main concern.
Yes, I realize I'm getting pretty abstract here. That's what defining requirements does to a fella. You should be lucky I'm not wearing a garbage bag for pants and screaming about the New World Order. Unfortunately for all of you, I'm not done with my requirements pontifications yet. Perhaps even more unfortunately, I'm keeping the punch and cookies for myself.
Recently, a colleague at work and I have been talking a lot about computing prime numbers. Specifically, his goal is to find the next largest prime number. Why? For the prime number groupies, of course. The current largest prime is somewhere in the neighborhood of 6 million digits. Through schooling and my own personal endeavors, I know a fair bit about this stuff, so I thought I'd share some here.
Think about a number that's one hundred digits long, something like 2 * 10^99. That's a big number. In fact, it's a huge number. According to some sources, that number we just created is several orders of magnitude larger than the number of atoms in the universe. When it comes to the world around us, we're not just whistling dixie when it comes to a 100 digit long number.
However, when it comes to prime numbers, a 100 digit number is nothing. Really, finding anything under several thousand digits is about as impressive as beating Jessica Simpson at Risk. That's a whole lot of digits, though. You have to take 100 instances of that 100 digit number, string them together, and then you'll have something of interest.
But even then, you're still incredibly far from the record. Right now, we've got a number that's 10,000 digits long. In order to get up the record, we'll need to take 600 instances of that 10,000 digit number, string them together, and then we're close. The numbers you're dealing with now are as large as any number anyone has ever used for anything.
Alright, so we've got our 6 million digit number. How do we store it? Let's try to store it in memory.
Being smart computery types, we know how to determine the max calue that a set of bits can hold; we just make use of powers of 2, remembering that our starting point is 0, not 1. One bit can represent the number 1, since 2^1 equals 2 (thus a spot for 0 and a spot for 1). Ten bits can represent 1023, since 2^10 equals 1024. That's easy enough. If we can just multiply 2^1,000,000, maybe we can start to get an idea of how many bits we'll need.
Err, there's a problem there: there's no easy way to calculate 2^1,000,000. You certainly can't fire up Windows Calculator and expect something to get a result. Compared to what we have to do, that's a pretty trivial calculation and we're still at a loss as to how to compute it.
That's the difficulty of this task. The operations are all simple: it's pretty much just division and multiplication. But on numbers this big, it takes an incredible amount of time. In order to do it quickly, we've got to do it crazily. Over the next couple of posts, I hope to introduce a few quick, crazy ways of computing prime numbers. Due to the terms of service here at codypowell.com, I can really only promise the crazy part.
No vloggy last week while I was out of the country. I'm back now, though, so you better watch your step.
I never took a class in school about databases. The meager amount of info I possess derives entirely from my idiotic attempts to interface with those wicked beasts. At work, we recently added a really sharp DBA. Since I ride the database short bus, I've been trying to latch onto him like some sort of parasitic howler monkey and suck as much knowledge as possible from him.
Well, in one of these sessions recently, we got into a topic I've never really understood: indexes. Specifically, we were talking about the difference between clustered and non-clustered indexes. Now I could give the textbook definition of both, but I never understood how a database (specifically SQL Server) differentiated internally between the two. Why does one sort faster than the other, and why can you only have one clustered index on a table?
Between him and some subsequent research, I think I've finally managed to grasp it. If a table has a clustered index, the data is stored as a B-tree with the leaf level nodes containing the data pages. If a table has a non-clustered index, the data is still stored as a B-tree, but now the leaf level nodes contain index rows. The index row is used a row locator, pointing to the actual data row containing the key value.
To simplify that (or amplify the geekyness one billion fold), a non-clustered index is a reference type, while a clustered index is a value type. It makes sense to me then that you could have many indexes that are references, while only one that contains the actual data. An actual database guy would probably tear me a new one over my treatment of the whole thing, but as long as this is my website, real database guys aren't allowed.
Good gravy, do I have a debugging tale to relate to all of you! If that's not a way to get an audience revved up, I don't know what is. I maintain some legacy code at work, and we were recently going through the last round of bug-fixes on it. I applied the fixes and tested them out on my machine, and it worked pretty well. Pretty well, of course, because it's legacy code and there's always one or two things in legacy code that make me stop and say, "Wait, do what now?" Anyway, shortly thereafter, I sent it to the tester so he could look at it. Immediately after he ran it, the entire thing exploded spectacularly.
Basically, the code interfaces through the serial port with these little manufactured devices; you use the code to transmit commands to the device. Well, when the tester began running the app, he noticed that one specific function didn't work for one specific device. If he tried another one of the devices, it worked just fine. I tried it out on my machine, and everything worked for both devices. I knew he wasn't just inventing the bug, so it was at this point I became very, very scared.
After tinkering for a little bit, we both huddled around his machine, hooked up the problematic device, and ran the code in the debugger. Surprise, it worked just fine. However, if I compiled the EXE and put it in another directory, it wouldn't work. I was now completely confused. Unless a master genius was at work, it just didn't seem logical how such an error could exist.
We butted our heads against this for hours. We had an idea of where the error was occurring, since we both knew the flow of the program. Knowing that, it was still very difficult to proceed, just because the code is so complex. What made it all the worse was that we couldn't step through the code in the debugger because the damn thing worked in the debugger.
What I chose to do was to open up the code and insert lots of sequential print commands (ie, lines like "Test 1", "Test 2", "Test 3"). Onced I compiled the EXE, moved it to the directory, and ran it, I began to see where the problem was occurring. Slowly, over hundreds of these statements, the noose tightened until I could figure out what the issue was. It definitely wasn't quick, but it proved to be effective.
It turned out that the error was in a function that I was completely unfamiliar with. Each time the app interfaced with one of these devices, it wrote a line out to a text file just for that device. For some reason, it wrote that line incorrectly once in the cursed directory and could never read from it again. That error, once found, was completely consistent with the situation we faced: it only happened on his computer, in one directory, with one particular device. It didn't happen in the debugger because the debugger was working from a different directory. Duh!
Had it not been for the hundreds of sequential print statements, I've no idea how we could've solved this issue. Sometimes, when our tools are limited, you can fix bugs like you fire a cannon. Shoot once above it, shoot once below it, and then adjust your scope accordingly.
Here's an embarrassing admission: Alphabetical sorting makes absolutely no sense to me. Okay, that makes the problem sound worse than it actually is. I'm pretty comfortable when it comes to the A-Z part; in fact, I can recite the alphabet backwards quicker than anyone I know. But everything after that confuses me. Specifically, I mean when we have to sort based on the non-alphanumeric characters. You're confused, I'm confused, let's look at an example.
Here are three strings:
test
test 0
test-1
If you threw those into a database table (or just created files with those names) and sorted alphabetically, they'd display exactly as I have them listed there. If we alter the strings just a little bit, it gets drastically weirder.
Let's say we add a period and an a to the end of each, so they're now:
test.a
test 0.a
test-1.a
Now sort alphabetically. The results:
test 0.a
test-1.a
test.a
Isn't that weird? We add the same two characters to each string, and suddenly the first result jumps down to last.
You can make it even weirder. Alter the strings slightly, so that the dash is located in a different string:
test-0.a
test 1.a
test.a
Sort alphabetically, and it's now:
test 1.a
test-0.a
test.a
Wacky! After messing around with this for 10 minutes, I successfully disproved gravity, thermodynamics, and the electoral college.
What's going on here? I have absolutely no idea, but this oddity does rear up occasionally to bite people in their rears. One example might be a developer who saves revisions to his specs with numbers (ie, he'd have db schema.doc, db schema 2.doc, db schema 3.doc). Well, with this loony sorting, I bet he'd open up the wrong document a lot, simply because the order of the documents is contrary to what we normally expect in a sort like that.
Anyone have any ideas on the crazy rules behind this? It's probably near the bottom of the list on the world's greatest problems, but it is interesting to play with.
I found an interesting discussion on the JoS forums today on the necessity of using brackets in your if statements. To me, it's mind-boggling that this is even an issue. The hoopla is whether a programmer should be shot for typing
if (i != 0)
foo(i);
instead of
if (i !=0)
{
foo(i);
}
The worry here is that the coder may mess up later if she needs to add another statement under the if condition. If you opt for the first route, add your statement, and forget to throw some brackets around the whole thing, you'd introduce a bug. I understand the argument, but how often does this occur? I've never seen it. It seems to me that you're not expecting much competence in your developers if you're mandating trivialities like this.
I write many if statements without brackets. For me, seeing code like that implies simplicity; there's one statement under the if condition and it's a no-brainer. That's how I've always coded, and for me, it makes the code easier to read. If my boss were to start peering over my shoulder and barking at me every time I used this tactic, I think I'd be a little insulted. How much faith do they really place in me if they can't rely on me to write a simple if statement?
Making such a big deal over such minutia is a trade-off. On the one hand, you may be preventing a few rare bugs. By doing so, you risk alienating the folks in the trenches. Is that a worthwhile transaction?
Recently, I talked a bit here about technical interviews, and my experience with them. Well, we've done a few more interviews at work, and I now have a couple more precious diamonds to share with the people of the internet. And trust me, they're so diamondy, Scrooge McDuck would be tempted to dive into them and swim around for a while.
Diamond the first: specific questions rule. I've noticed that when you're speaking in very general terms (such as about the development process or your experiences in the past), you can sound good without saying a lot. (That's what I do here a lot, except I just say a lot and sound like an idiot.) Anyway, in those interview instances, the only way to separate the sizzle from the steak, as it were, is with specific, technical questions. I did this through a list of coding questions that a couple of us developed. They were heavy on pseudocode, OOP, and then a few language specific features. The good thing about these questions is that they had right answers, so we had a way of measuring the knowledge of the candidates aside from how pretty the answers sounded. If anything, it seems like there may be an inverse relationship between the ability to answer a vague question and the ability to answer a specific one. I don't know how you could figure that out without a couple of hard questions whose answers you knew.
Diamond the second: if the specific questions don't work out, you need something else to talk about. Interviews are long, usually at least 30 minutes. If you opt for the specific questions route and the candidate is having a really, really tough time answering them, you're going to have a crapload of awkward time. In those cases, I've found it's good to go back to asking the vague, general questions. Let the candidate leave thinking that he bowled you over at the end, as opposed to him leaving depressed and looking for the nearest store that sells cannonballs.
Diamond the third: let the questions do their job. It's not your job, as interviewer, to cut the candidate down to size. That only makes things uncomfortable for both of you. If someone has an attitude and you want to cut them down to size, ask them some specific, technical questions. It could be that they're a genius and have a very good reason for such an attitude, or it could be for something else entirely. Most of us aren't psychiatrists, so it's not our job to figure it out. The candidate has to impress you, not the other way around, so ask the questions, let him answer, and get on with your life. There's nothing to be gained from grandstanding or proving yourself to this stranger.
And now, my brain is empty. There's absolutely nothing left in there, as it all just got dumped out for you. For proof, I point to the fact that I just tried to eat my stapler. Interviewing is interesting, especially if you're one of those folks whose spent most of their time answering the questions rather than asking them. By doing a few and analyzing the results, I'm not nearly as dreadful as I used to be. The folks at the cannonball store may say otherwise.
As someone who spends 40-60 hours a week developing, I like to rip the vlog from real life. You can always tell when I'm not being productive at work, because then all of the entries here are about how much I hated Delta Burke on Designing Women. This week at work, we're gearing up to do some interviews for an opening on our team. The way we do it at work, the higher-ups ask the important, character-related questions ('Where do you see yourself in 5 years?'), while we technies get a chance to dig into the nitty gritty with the candidate ('If you had to marry one video game character, which one would it be?'). My own answer would be King Hippo from Mike Tyson's Punch Out.
Anyway, thinking about the whole interview process has got me to thinking about the ideal way to interview a developer. I've read lots of sample questions on the web, and I can group most of them into two groups: the trivial and the absurd.
Here's an example of the trivial (in C#): What's the difference between System.Array.CopyTo() and System.Array.Clone()? I don't understand what this question is supposed to tell you about the candidate. If she were sitting at a computer, she could probably figure that out in 60 seconds; it'd actually be a good question if you allowed the individual to figure it out that way. Without that, it's just a trivia question. It doesn't tell you anything about the person's skills as a developer, just about that person's ability to memorize footnotes.
Now an example of the absurd: if you had an infinite supply of water and a 5 quart and 3 quart pail, how would you measure out exactly 4 quarts? Unless the person is applying for chief water measurement officer, I don't see the relevance here. It's a riddle, some would contend, and it reveals a lot about a person's problem-solving skills. To me, it seems kinda masturbatory. Questions like these serve to inform the candidate of just how clever the interviewer is, not the other way around. That's not the point of an interview.
If you really want some insight into a person's problem-solving skills, as well as her knowledge in a particular technology, I can think of a better way to do it. How about a relevant, open-ended question? Maybe something like the following:
What's one project you've never gotten around to working on? Let's say you decide to start work on it one weekend. You can choose whatever technology you want to complete it. Walk me through your creation process.
I have very little experience as an interviewer, but quite a bit as the person being interviewed. When I was looking for a job, I know I would've really responded to a question like that, just because it's fun to think about. For me, that's not exactly the case when thinking about measuring water, given limited equipment. Any interview is bound to be imperfect, but you can at least attempt to learn something relevant about the person. Unless, of course, they answer the question correctly about marrying a video game character. If you hear someone else say King Hippo, that's a one way ticket to a corner office.
I'm not quite ready to continue working on error-handling; I trust all of you will have the courage to go on living until I can proceed with my work there. Instead, here's an interesting note I found about recursion in Code Complete:
"One problem with computer-science textbooks is that they present silly examples of recursion. The typical examples are computing a factorial or computing a Fibonacci sequence. Recusion is a powerful tool, and it's really dumb to use it in either of those cases. If a programmer who worked for me used recursion to compute a factorial, I'd hire someone else." - Steve McConnell, Code Complete, p. 397.
Someone's got a bee in his bonnet when it comes to recursion! And I wonder, if you had a bee in your bonnet when it comes to recursion and you take that bonnet off, do you find another bonnet containing another bee? Just food for thought.
Anyway, I do remember the first example of recursion I saw in college, and it was for computing Fibonacci numbers. The only examples I actually remember now are the really simple ones that McConnell mentions. The entire class had a hard time understanding exactly why we needed recursion in those situations, when we already knew about loops. That's one of the points that McConnell makes, that those simple recursive methods are harder to understand than the iterative version of those methods. He also says they're slow and they make the use of run-time memory unpredictable.
After I read that, I began to wonder just what recursion was good for. I know it's good for binary trees and whatnot, but it seems like there are almost always other, simpler approaches we can use. Then, today at work, I got in a tricky spot where I was trying to write some code that dealt with MIME attachments. I tried all kinds of loops and loops within loops and super mutant loops, and I just could not make it work. I was this close to turning my King Nerd crown and sulking home.
But then, on a lark, I tried to write the function recursively and it simplified the matter immediately. Suddenly, 150 lines of code went down to 15 lines. I could once again wear my crown with pride.
My point? I don't have one, except that I found it ironic that recursion came in handy just as I began doubting its validity entirely. It's like the developer gods were trying to teach me a lesson: just because you only know a few dumb applications of an idea doesn't mean the idea is completely worthless. Fine with me, unless that idea is flossing regularly or exercise; to me, those will always remain foreign concepts.
Last week, I said that error handling interested me, and that I'd probably delve into it some more here in this space. Well, let the record show that when I issue vague declarations from an unpopular website, I stand by them. Today, I'd like to discuss a specific error-handling technique of mine and why it's probably terrible.
My thesis with all of the error handling business is that most of us don't really know what we're doing. When we do design and code, we focus on the sexy stuff, like the cyborg interface to our missle defense APIs, not boring crap like error handling. That's maintenance, not development. Let the users find the errors, and then we can fix them while shaking our fists and yelling, "Learn to type, idiots!"
Since we don't pay attention to error handling, we get into bad habits; case in point, yours truly. I don't consider myself to be a complete idiot when it comes to programming; I can, after all, manipulate the LOGO turtle with the best of them. Nevertheless, I recently realized that one of my main error-handling techniques is completely idiotic. The only reason it works is because the code surrounding has been sufficiently idiot-proofed. That's probably not the right way to do that.
Most of the code I write accesses a database. Since those databases are pretty normalized, I write a lot of methods where I need to look up an identifier for some piece of data. One example: we take a status description ("Active"), and we need to return the status id for that description. Not only is it not brain science, but it wouldn't even qualify as pinkie toe science.
It is simple, but there's an issue here: what are we supposed to return if we don't find a record for that status description? Assuming we're returning an integer, I always returned -1 for that situation. The methods that call that status lookup process are aware of what -1 means, and so they act accordingly if they receive that as a return value.
At first glance, that's not too bad. It's not too good, but I'm not sawing the legs off of kitties or anything like that. But then, when I started thinking about it, I began to realize it was all wrong.
First, I'm using the same variable to return a value AND communicate an error code. If you were just picking up the code, how would know whether that value is an error or a valid return value? Basically, you'd have to come to my house and ask me, which would probably be an inconvenience to you. There's no instrinsic mechanism to inform the user that -1 is an error.
Second, this shows some bad design on my part. If I were to change the error code to be -5, I'd likewise have to change all of the methods looking for -1. It's not a very good example of information hiding, one of the key points behind object-oriented design. The idea behind information hiding is that the interface to a class should reveal as little about its inner-workings as possible; that maxim flops entirely here.
Okay, I think I've effectively demonstrated that the work I did was crappy. Crappy yes, but I recognize it's crappy and that's the first step towards recovery. How do we fix it? How do we cleanse the code of my good intentioned, but ultimately yucky error handling implementation? I have a few ideas. But to see these ideas, you will have to wait until next time. (In advertising terms, I am dangling the carrot there. Visit obsessively, or suffer sleepless nights for the rest of your life! Mwa ha ha ha!)
As I mentioned last week, I'm reading Code Complete right now, one of the great texts on software construction. In it, there's a lengthy chapter on error-handling, exceptions, and defensive programming (Ch. 8). Being the master of causing errors, it only makes sense that I also become the master of handling these errors. I found that section particularly interesting, largely because there's so much to it. Think for a moment about how much code you've written to handle errors. I write stuff like that almost every day, but I can't think of any shining (or even good) examples from all of that code; I'd wager my Yoda doll that there are others who operate similarly. Why is this? If we're writing so much error-handling code, why aren't we better at it?
Part of the issue is that error handling is never addressed as a real problem. I've taken plenty of computer science classes in my day, and while I've learned plenty about merge sorts and how to represent numbers in IEEE floating point format, I don't remember ever covering the right way to handle errors. Meanwhile, how many times have I had to implement a merge sort? I tried to do it for fun to sort the size of my socks, and when I woke up 8 hours later, I was in the neighbor's lawn. This subject deserves some class time (not my neighbor's lawn, but error handling).
The other part of the issue is the scope of the problem: it's humongous. Errors can occur in any part of a package, and all of these errors have to be handled in a logical, expected manner. Developers have to be both thorough and consistent across a gigantic chunk of code; that's not easy. And you can't just pick one or the other, you have to shoot for both. If you only opt for thorough, then you'll be rereading a lot of code to see how the developer handled the error in that specific instance. If you only opt for consistent, then some errors will make their way to the user. It's like a peanut butter and banana sandwich; if you don't have both ingredients, you're simply fooling yourself.
There are a lot of tools at our disposal here (exceptions, assertions, etc.), but we need some sort of framework for utilizing them. I think Code Complete provides a good start down that path, but I want to think about it myself and come to a few conclusions. Over the coming days, my plan is to write and dissect a couple of examples here, with the aim of educating myself and confusing/annoying the good people of the internet. It's a tall order, but if anyone were ever capable of edufusoying people, it's me. (And, of course, the merge sort.)
Okay, I'm having a hard time today. I am compelled to put something up here, a little dusting of that Cody Powell pixie dust, but I can't think up anything good. Looking at the archives, you can see that rarely stops me. Today, in lieu of an earth-shaker, how about a cool tip for Visual Studio .NET? And if that's not enough, then how about an ice cream sandwich?
Allow me to be honest here: sometimes I get in a hurry. I think that, along with the love of fried cheese, is only human. Occasionally when I'm work, someone will come to me and say they need some code RIGHT FRICKIN' NOW. Genius usually fails me in those moments, so I give them something that works. It works and it's serviceable, but no one is going to propose to it because of its beauty (I should note this happens rarely in software development anyway). Whenever I do one of those rush jobs, I like to make note of it in the code so I can go back and fix it later. Whether I go back and fix it later is another matter entirely, but that's what I like to do.
My problem was that I had a hard time finding those less-than-great chunks of code when I went back later. Unless I stuck to some standard comment format for my hacks, it could take me quite a while to locate them. Sure, I could think of a few choice phrases with which to mark them, but I began to worry what our clients would say if, every thousand lines of code, there was a comment that read "Developer's Note: what follows is a flaming pile of poop."
And then today, when messing around in Visual Studio .NET, it hit me. Not the IDE, but the way to comment my hacks. In Visual Studio, there's a task list into which you can add tasks you need to tackle. If you have that Task List open, you can right-click on it and go Show Tasks->Comment. Don't worry, we're not to the cool part yet.
Once you're showing your Comment tasks, go into your code, find one of your cruddy sections, and type "///HACK " and then a brief description of the yuckiness. Your HACK comment then appears in the Task List, as if ordained by some super powerful wizard! Too cool. Two other built-in keywords are TODO and UNDONE. I've been using those terms in my code for the past couple of months, and it really, really helps me in determining what work is left if I haven't looked at the code for a few weeks.
It's completely possible that this feature has been around a while now, and lots of people are already using it. It's my site though, so the posts can be as obvious as I want! And if I want to lie about giving you an ice cream sandwich, well, I can do that too. Here at codypowell.com, we play by prison rules.
Last night, I was doing some work in MATLAB related to matrices. What was I doing? I don't know, clearly I need some hobbies. Specifically, I was trying to compute the eigenvalue for a matrix closest to a certain value. There's a formula for this that's well understood, the shifted inverse power method. I had a hard time translating that method into an algorithm, however. After many hours of typing, cursing, and weeping, I hit upon the answer. I will thus present it here, so the nerds of the world can soak it in.
%Modified Shifted Inverse Power Method
%Adoped from Dr. Kincaid's pseudocode, UT CS dept.
%Supply a matrix A, a vector x, the number of iterations
%desired, and the value for which you want the closest
%eigenvalue.
format long;
%set up the matrices.
[n,n] = size(A);
B = A + abs(near)*eye(n);
C = inv(B);
%perform the iterations.
for k=1:steps
y = C*x;
r(k) = x(2)/y(2);
x = y/norm(y);
end
%In case the series is slowly converging, we do some Aitken
%acceleration here.
for k=3:steps
s(k) = (r(k-2)*r(k)-r(k-1)^2)/(r(k)-2*r(k-1)+r(k-2));
end
eig = s(steps) - near;
Man, who among us doesn't feel the adrenaline when viewing that function? To verify, A*x should equal eig*x. If not, either your computer is broken or I messed something up. One is much more likely than the other.
In the past, I've tried to experiment a lot with Linux. Invariably, these experiments fail, mainly because I have no idea what I'm doing. I'll get 90% of the way to a working desktop, but in trying to get my sound card to work, I'll trash the entire hard drive. Woops. And then I repeat those steps a few times until I relent and turn my hard drive over once again to Windows Solitaire. Like washing my car, it's something I do twice a year like clockwork.
For a project I'm currently working on, I needed Redhat Fedora installed on my machine. There was great gnashing of teeth when I first heard that; history has shown I can't control anything more powerful than an etch-a-sketch. However, I soon learned that someone else, an honest-to-goodness expert, would there to do all of the hard installation stuff and I immediately began to ungnash my teeth. And you know what, after he installed it, everything worked immediately. My USB mouse worked, my sound card worked, my network card worked. I was living the dream, brothers and sisters.
And then I took the box home so I could do some work there, and this is where the fun begins. Once I loaded GNOME up, I noticed that it didn't seem to be repainting things correctly. Whenever I tried to pull down a menu, it'd be transparent. The same thing happened with buttons, and I wouldn't be able to see either until I moused over those UI elements. It was very, very odd. So odd, in fact, that I quickly went from pleasantly bewildered to pants-wettingly confused.
I tried a hundred different video card/monitor combinations, but I couldn't get anything to work. I begged for mercy at the feet of my guru friends, and they were baffled as well. For whatever reason, it looked like there was a blood feud between Redhat and my Intel 810 video card.
Eventually, after one hundred billion searches on Google, I stumbled across a newsgroup posting that contained the answer. I share it here in case anyone else has a problem with their Intel video card and the window managers contained in Fedora Core.
In /etc/X11/xorg.conf, you need to make a small edit. There's a block of the file that looks like this:
Section "Device"
Identifier "Videocard0"
blah blah blah
EndSection
Somewhere before that EndSection, you need a line that says
Options "noaccel"
Once you have that, restart GNOME/KDE/whatever and get ready to have your pants blown off. Not literally, but computationally, as a brand new world of viewable menus and buttons will open itself up to you. It's a powerful experience, and one I never would've figured out without a whole lot of help. So, if Linux wants to scare me off this time, it's going to have to try something a little different. For example, it will have to prevent me from installing any new applications, as I'm currently experiencing. I'm convinced this is just a minor stumbling block, though. With buttons and menus on my side, who can stop me?
As I mentioned a while back, I've been getting more serious about using a scripting language for some of my programming duties. I've done a few simple scripts, but nothing to wet my pants over so far. Until today, that is. And today's pants wetting had absolutely nothing to do with an actual script, but a really cool use for a scripting shell and a way to eliminate the plague that is the Windows calculator from my daily routine.
Like a few other developers, I have to write a lot of number crunching code. I'm not modelling the explosions from Dom De Luise's bathroom or anything complicated like that, just munching on a few formulas. I soon discovered that no matter how good I thought I was at mental math, I still had to check the results of the formula with an honest-to-goodness calculator. Well, since my development machine is a Windows box, I have always used the calculator that's bundled with Windows to check my results. Let me tell you this right now: if the folks at the Apollo project had used the Windows calculator to get us to the moon, there'd be a bunch of monkey corpses in orbit around the planet.
The Windows calculator works okay for really simple calculations, but it's a complete donkey when you get to "complicated" things like negative numbers and parentheses. Also, it's very mouse intensive, which doesn't work well for a keyboard fiend like myself. To prove all of this, just try typing in -1 - -2; I wouldn't exactly be betting my life's savings on the results of the Windows calculator.
Today, the formula I had to check was a pretty simple one:
x - abs(z - y)
That's not exactly something that would keep Euler up at nights, but I knew it would cause the Windows calculator to foam at the mouth until animal control could put it down. In fact, looking at the program now, I can't even see how I would do absolute value. What I wanted was just a simple, command-line calculator, but I didn't really feel like searching and then downloading one, or writing one myself. What could a single, pathetic, shadow of a man like myself do?
Here, inspiration struck. I started up Python Interactive Shell (aka Python.exe). When you're in Python's shell, you can run individual statements interactively. That's exactly what I did, first assigning a few variables and then running the formula. It worked perfectly the first time. At least I think it did; it was hard to see through the tears of joy.
Today, I found a benefit of scripting languages that I had never previously considered: quick mathematical evaluations. It might not sound like much, but to those of us who have been slogging through the Windows calculator ghetto for years, it's like a lobster buffet.
I said I was working on a massive entry and I still am, but it shall be superceded today because I just can't keep this to myself. Much like finding the Wolf Man hiding in your bath tub, it's too weird for me to keep this to myself.
As part of a project I'm working on, I needed a specialized installation of Fedora on one of my development machines. Thankfully, a fellow member of the project had already scripted the whole installation out and written it to DVD, thus making it one of the easiest Linux installations I've ever participated in. It's funny how easy things get when I'm no longer allowed to touch the keyboard.
Anyway, after we got everything installed and operating, I brought my machine home and booted it up so that I could do some poking and prodding. It booted up great into GNOME, and then took my username and password with nary a hiccup. And at this point, the machine elected to soil itself. After I logged in to the desktop, I couldn't seem to do anything. I would click on a menu, and nothing would appear. Or I'd double click on an icon, and the outline of a window would appear but I wouldn't be able to see anything inside that icon.
Compounding the weirdness, UI elements would start to appear if I moused over a certain part of the window. Example: I'd be looking at this blank window, and then I'd move my mouse over the corner of the window and suddenly I'd see an OK button right under my cursor. Menus worked the same way, in that if I were to move my mouse down where the menu should be, the menu items would start to appear. Kind of weird, but I've certainily had stranger things happen to me before (I refer back to the Wolf Man in my bath tub).
At this point, I figured I could probably solve this problem by myself. After all, I have the INFORMATION SUPERHIGHWAY at my finger tips! I fired up a trusty web browser, and searched for "gnome docs". From that, I derived no prosming results. I fine-tuned my query a little bit, changing it to "gnome help". Again, no luck. I seriously began to wonder whether GNOME was a piece of software, or a product of my own delusional mind.
It occurs to me that if anyone wants a reason why users aren't flocking to open source for their personal operating systems, they may want to reread the preceding paragraph. I tried the two most obvious web searches for help, and I got nothing. Then I tried the project's website, and even I couldn't find anything approximating documentation. This is one of the most popular pieces of software in the world; why make it so hard to read about it? Is the project run by the Freemasons or something?
After a few hours of searching, my problem is no closer to being solved. I have, however, found the GNOME docs. And just in case Google happens to be watching, let me do that again: GNOME docs.
Okay, I'm working up a monster post, but I wanted to do something shorter first. And by monster post, I mean it. This post will eat your young and then storm the Count's castle. But first, a little something to do tide you over.
I was stuck in an unlikely situation lately, where I had to transfer a lot of data from MySQL to SQL Server. If you search online, you'll see a lot of results for that, but not in that order. Everyone has written about going from SQL Server to MySQL, not the other way around like I wanted. In fact, the only real bit of info I could find was on the Microsoft website (big surprise). It was certainly useful, but it was way too long. I've decided to simplify it in a few short steps.
Step 1. Install the ODBC adapter for MySQL off of MySQL.com. Create an ODBC connection to your MySQL database.
Step 2. Create a new DTS package in SQL Server. You'll two connections: one to an ODBC datasource, and the other to your SQL Server.
Step 3. Create a Transform Data Task, going from the ODBC connection to SQL Server.
Step 4. Select the appropriate Source tables in MySQL, and point them to the correct Destination tables in SQL Server (you can instruct the DTS package to create these tables if needed).
Step 5. Let it rip.
Hey-o, that's some simple stuff! And for those of you in the Windows/SQL Server world who aren't familiar with DTS packages, you should definitely give them a look. They're a really simple, powerful way to transfer and transform data from one db to another. The best intro I ever stumbled across was in Robert Vieira's SQL Server book.
Yes, you could certainly write the code yourself to do this transfer, but I have better things to do with my time. I have cookies to eat, corndogs to burn, and monster posts to create. Here are some good DTS resources:
DTS Best Practices
SQLDTS.com
Good day, gentlemen and gentleladies, I'd like to discuss a little bit about installation packages today. If I had to pick the one thing I like the least about my job, it's cleaning out the hogs' slop bucket. I hate to say it again, but why does a software company even need a hog pen? Anyway, a close second on that list is making the installation packages for the software that I write. Those setup.exe's are certainly important to create; if the users couldn't use my software, I'd essentially then be getting paid for blowing my nose. The irony is that as important as those installs are, they're a complete pain in the rear to make. There are a myriad of tools you can use to create these setups, but in my professional opinion, they are all converge on crappiness.
One of the most popular tools for creating install packages for Windows is InstallShield. I don't have any numbers on this, but it seems to be the most prevalent tool from my own experience. Speaking for all InstallShield users everywhere, how on earth did this happen? To me, that's like licorice-flavored jelly beans taking the country by storm; there's just no reason why something so lame should be so popular.
I realized this the first time I ever used InstallShield to create an install. It was a little complicated, but I managed to get something built after a couple of hours. I did a test install of the package, realized something I had done wrong, and then went back to InstallShield to fix it. So far, InstallShield and I were as thick as thieves. Once I made the fix, I tried to build the setup again, and here's where InstallShield lobbed a pie at my face. Apparently, InstallShield Developer can't create a setup.exe in a directory if you have that directory open in Explorer. That may not sound bad, but in actuality it's like french kissing Darth Vader. Allow me to explain.
I rarely do InstallShield; my time spent there may average out to half a work day each month. So, each time I build a new package, it usually takes a few times for me to get it right. I suspect this is the case for a lot of other InstallShield develoeprs. By instituting that completely bizarre rule about not having certain directories open in Explorer, InstallShield makes a difficult process even more onerous. If I'm going to be rebuilding this package several times in a row and then installing it, it's only logical to keep that directory open in Explorer. Perhaps I wouldn't if InstallShield placed the setup.exe file somewhere other than at the bottom of 10^100 subdirectories, but that's just the way InstallShield rolls: slowly and with total disregard for others, like a 90 year old at the wheel of her Cadillac.
Does any other compiler work that way? Compile something with Visual Studio .NET, or gcc, or Java. Does the compiler give a flying foofoo what directory you have open? Why on earth would it care? If they don't work that way, why does InstallShield? Someone get me Encyclopedia Brown; I'll never solve these mysteries on my own.
On top of all of this, I return to my original question: why InstallShield? How did something so intolerable rise to greatness in the world of software development? Does the InstallShield CEO have incriminating pictures of Bill Gates and his french maid? Or is it possible that creating setup packages is really that difficult? If anyone would like to beat me over the head with a cluestick here, I'd really appreciate it. And until someone does so, I'll be tending to the hogs.
A colleague made an interesting point today. At work, we're supposed to be delivering a new piece of software in the near future, and so the task was assigned to a small team. Over a span of a few days, these folks sat down with a whiteboard, a laptop, and a projector, and worked through what this software would do. They had ideas for all of the screens and functions, and they even started pseudocoding some. Once they were finished, they thought that most of the work was completed. True, they didn't have any code yet, but they had the ideas and the structure in place. Prepare the cradle, because that baby's ready for beddy-bye time.
The end result of these meetings was a big document that detailed everything about the software. Just translate the document into code and everyone could move on to something new and sexy, like how to make robots mud wrestle. However, it turned out that translating that document into code wasn't exactly easy. In fact, it was just hard enough to make the process frustrating.
Apparently, working sequentially through a spec document like that isn't very conducive to programming. A lot of times when someone is programming something, they'll carve off a chunk of functionality and work on it until it's done. That's what the developer here wanted to do, but that wasn't how the document was laid out. Instead, all of the functionality was interspersed throughout the document. There could be three consecutive documented functions, and the functions could be for vastly different parts of the package. Perhaps one was for button handling, one was for inserting records into a database, and the last was for stripping characters from a string.
All of those are valuable functions to have, but if you were coding without sucha document, you usually wouldn't do those three in succession. Instead, you might do the button handling with the rest of the UI code, then all of the database functions, then the string functions. It's much easier to get on a roll like that. If you constantly jump from one functionality group to another, that flow is interrupted because you have to continuously refamiliarize yourself with that part of the code. I feel a metaphor coming on.
It's like making a salad. When I make a salad (which admittedly isn't very often), I tend to focus on one part of the salad at a time. I don't tear off a piece of lettuce, chop one slice of tomato, drop in a few specks of pepper, mix all of that together and then repeat 50 times. No, I tear all of the lettuce at once, then chop all of the tomatoes at once, etc. It's a lot quicker that way; I minimize the lost time that comes with switching tasks. And then, when I'm done making the salad, I dump it all in the trash. Health food and I get along like Bill O'Reilly and Flava Flav.
There's no question that thorough specs like that make the developer's job easier. However, if they're not organized very well, they can also be a hindrance. The key idea, I think, is to be flexible enough to work those documents into our regular working routines. Allow the developer to change the structure of the document as she sees fit, and give the document creator a few tips on the best way to organize the functionality. Otherwise, working from the specs could take just as long as not working from the specs.
I will be honest: lately, I've been neglecting the vlog a little bit. Unfortunately, real life often gets in the way of shaking my web thang, and I end up treating the vlog like a rented burro. Oh, but you are much more than a rented burro to me, vlog! I will vow to do better.
Recently, I managed a free subscription to ACM Queue by filling out a form on their website. That's awesome; Queue is one of the best programming magazines out there, and I got tired of waiting for all of the articles to become available online. Well, the March issue is all about patching, which is pretty interesting in itself. Since I am completely incompetent on the subject though, I have nothing to say about it. What I would rather comment on is the editorial at the end of the issue by Jef Raskin (who sadly passed away quite recently; the technical world is surely worse off without him).
The title of the piece is "Comments Are More Important Than Code", and it lays out the idea that the best way to go about development is to document first, then code. It's a good idea, I think. It forces the developer to think through what she's doing, and discourages a "shoot from the hip" mentality. Also, it makes maintenance much, much easier because a thorough explanation would exist for each piece of complex code. I like the idea a lot, but I don't think it would work well in practice.
Let's assume we all shift to this mode, where we're commenting first and coding second. What happens the first time an emergency occurs? Let's assume it's something really critical like a stock trading system, and each minute of downtime represents a cost of thousands. That's a lot of halibut. Let's say you're the guru of the system, and you could implement a fix in 2 minutes. Maybe it's a tricky fix that only a fellow guru would understand, so in order to hold true to Raskin's idea, the comments would have to be lengthy and thorough; perhaps it'd take 3 times as long to comment your change as it would to actually perform the change. How do you justify that additional downtime? Would you be comfortable going to your boss and explaining the loss of thousands to her? I wouldn't. I get antsy going to my boss when we're out of Kleenex, so telling him I intentionally lost thousands more than what was necessary is enough to give me the vapors.
Most of us would probably just make that change, and let the comments slide that one time. But what happens then? Your comments, which are supposed to be the heart of the system, are no longer current; they don't reflect the current system, so Raskin's whole concept of commenting is undermined. Each time you looked at the comments, you'd have to compare the explanation to the actual code to see if they're correct that time. Now your job is twice as complicated. To me, that's not a viable solution.
Now, Raskin certainly knows what he's talking about more than I do. He was, after all, the guy who started the Macintosh project, whereas my biggest accomplishment is winning Wimbledon on Very Hard in Virtua Tennis for PS2. I think his idea is a good one, and would almost certainly result in better software products. I just don't know how feasible it is in reality, though. It's hard to justify another level of complexity in an emergency, and it's during these emergencies that our jobs are the most visible. It's critical there to deliver quickly and adequately, not necessarily to deliver brilliantly.
As developers, we invest a lot of time into creating these great processes, only to discover these processes aren't helpful during times of crisis, when a process should matter most. How do we fix that? Do these great processes lack the flexibility that our duties necessitate? I don't know the answers to these questions, but I try to give them an honest effort here on this site. Virtua Tennis is another matter entirely; any questions there could be answered in two shakes of a lamb's tail.
One thing I often wonder about is code duplication. How many functions are floating around out there that determine if a string is a valid date? What about the number of functions that have been written to determine the last day of a month? I'm no professional counter, but I'd bet those functions have been written at least infinity billion times by the world's programmers. I conservatively estimate that I've contributed half of these. That's because every time I write something, I find it much easier to just rewrite those functions than to go searching through old code to see how I did it previously. Like a lot of the work I'm responsible for, I attribute this entirely to my own laziness and idiocy.
Clearly, that's a waste of time. If I devote 15 minutes each week to duplicating something that I've already written, that works out to be 13 hours worth of naps and tickle fights each year I'm missing out on. I've got to tell you, seeing that figure really steams my broccoli; nothing gets me more riled up than missing an opportunity for a tickle fight. There's got to be a way to avoid this code duplication. How do you do it, though?
Well, one idea would be to put all of your helper functions out on the web somewhere. Then, when you find yourself needing that particular bit of functionality, you could go to your favorite search engine, plug in a few terms, and locate what you've already done. There are some big flaws to this, though. First, you'd have to publish all your code to the web; that'd be hard to remember, plus your boss probably wouldn't like it. Second, you'd have to be able to locate the code once it's out there; it may take a few searches to get there. There's promise to this idea, but I will give it no higher than a bronze medal.
An alternative idea would be to create some sort of application to library your code. If you stick to some coding standards, you could have the library agent parse your code and automatically insert it into the library. Then when you need something, you query the library and see what's in there. This is more appealing in that the code doesn't have to be public anymore, plus there are no manual processes to remember. However, writing such an application could take a lot more time than you waste each year with duplicated code. Unfortunately, as cool as this idea is, it's a little too thorough. If you had a super-intelligent robot manslave, it'd definitely be the way to go, though.
What about putting all of these helper functions into a big class file that's included on all of your projects? Whenever you need a common function, you could just glance at that class to see if it's already in there. This would certainly be a lot quicker than writing a library application, but the downside is that you have to include that library file with everything you write. If it's a quick and dirty job, the library could be several times the size of the new code. That's not a very efficient use of resources, plus it's very unlikely that the programming groupies will flock to you if your Hello World! apps are 150MB. If you're not coding to impress the programming groupies, then I just don't think I have anything to say to you.
The best idea, I think, is to store all of this in a wiki. In just a few minutes, you can have a wiki installed and some categories set up to handle all of this. Also, the wiki could be private/public, depending on what you want. If you didn't want to remember to insert each function that you write, you could write something like the library agent that I mentioned earlier. It's easy to get going, and once you get it going, there's a lot you can do. In that respect, it's a lot like buying a deep fryer.
It's hard to tell whether this would save any time in the long run. Maybe it wouldn't, but at the very least, it'd keep me from wanting to bang my head on the keyboard when I discover I'm in need of a function that validates dates. Also, it's bound to win you a few points with the programming groupies.
On quite a few different sites lately, I've seen an ad for dice.com, which must be a tech jobs site or something. Anyway, the ad is in source code, which is a nice touch. Well, it would be a nice touch if it were well written. Let's take a look at the code.
It's a cool idea for an ad, but if it's going to pass muster with the raging dorks of the Internet, there needs to be some more attention to detail. The target audience here spends all day obsessing over minor details like that, so I think the only way to win us over is with a similar mania for correctness. Either that, or through gratuitous nudity; they're both highly effective choices.
Anyway, it just goes to show that the lesson applies to marketing just like it applies to coding: compile before checking in your changes. Even if it's a made-up language for a website ad, you can bet that some unfortunate soul with WAYYY too much time on his hands (see: Cody Powell) will eventually go looking for errors.
One of the classes I'm taking is a class on numerical methods of computing. Apparently, there's some pretty complicated numerical stuff going on inside of computers. This was surprising to me, as I figured my computer ran on jellybeans. Come on, where else are all the jellybeans going?
Anyway, the main application we're using for our labs/homework is MATLAB. I'd used Maple in previous math classes, but never MATLAB, so I was pretty jazzed to learn a little bit about it. Well, the first time our professor pulled up the application, something struck me. That something was a ceiling tile, and it hurt. At the same time, I realized that MATLAB looks very familiar. In fact, it looks like ... Python.
Por ejemplo, let's say you want to create an array and see how large it is.
In Python, it'd look like this:
In Matlab, it'd look like this:
A very simple example, but you get the point: the notation is kinda similar. Howevever, I didn't really know anything about Python's mathematical capabilities. After a cursory search, I didn't see any matrix functionality in the base or math libraries. When I got home from work that day, I decided to do a little research. Had the Python community created any libraries to make the language more Matlab-like? What about add-ons for matrices and graphing? Well, as I often do when I'm curious about something, I brought this question to the Oracle of Google, and the Oracle never fails to satisfy.
I found a few different items of interest. First, there's a library called NumPy, which has been around for a long time and offers all of the standard matrix functionality (it looks like it has since branched off into numarray). (I also found an older interface between NumPy and the Matlab engine: PyMat, which has very cool potential.) Second, there looks to be a nice library for Matlib-style plotting called Matplotlib. Third, and perhaps most impressive, is SciPy, a library of scientific tools for Python. From my cursory overview, it looks to be the most mature of the Matlab-like options for Python. Also, it looks like it is maintained here in Austin! Woo woo, 512 in the hay-ouse!
I had no idea that Python had such burgeoning scientific support. One of the issues I noticed thus far with Matlab is that it's not very programmatic in nature. For instance, if you're going to save a function to a file, it has to be named FunctionName.m. That's why I find all of these discoveries to be so exciting: combining the numerical capabilities of Matlab with the programmability and community of Python is a win-win. Not only that, but it's free!
To me, this is a great example of what can happen if a tool is extensible and open to the public. As a result of doing this, you may not be able to strut around town in a diamond-encrusted tuxedo, but you can successfully capture the minds of nerds around the world. To all of the programmers who made this functionality possible: thank you. To my professor: I have now found a whole new way to screw up my homework.
Recently, an acquaintance asked me if I'd be interested in doing some contract work for him. What he wanted was a database, along with a PHP front-end, that could store the hands dealt on an online poker website. I politely declined for two reasons. First, I'm so busy right now that I consider putting on pants a waste of my precious time. I've just been wearing potato sacks for like a week now, and I don't want to think what the next progression is there if I add in another activity. Second, I'm not sure how legit this activity is. The guys behind these sites probably have names like Guido the Lamprey, and I don't want any first-hand knowledge of where that moniker comes from. After I declined, I thought it over a little bit, how I'd design and implement something like this. It seems easy enough, but it took me a few tries before I got anything approaching decency.
If you want any level of detail whatsoever, you'd need the cards involved for each hand. What I slowly began to realize is that how you store the cards in the database determines a whole lot about your application. Let's say you decide to break the hand data into two separate tables: one table which contains data about the hand (like the date and site it was dealt), and then one table which contains the cards (we'll call this one HandCards). What does the HandCards table look like?
My first idea is that you could describe each card with a simple 2 character field. For each card, that field would contain something like '8C' for 8 of clubs or 'JD' for Jack of diamonds. Seems easy enough, but think for a second about figuring out the hands. For example, how would you write a method to determine if a hand in question is a straight? First, you'd have to dissect that card field so you're only looking at the first character. Second, you couldn't abstract it totally because you're not dealing with numerical values. The compiler has no way of knowing that K, Q, J, 10, 9 is a straight, so that data would have to be specified somewhere. Good glayvin, this is the path to madness and wearing sweatpants out in public!
How about, in HandCards, we add an additional field: numerical value. That way, if the user is dealt a Jack, you could stick an 11 in there to show that a Jack is one above a 10. There's a problem here, though: this design isn't normalized. Let's say an avid player uses this database. Over the course of time, they receive the Jack of Diamonds 100 times. In each one of these records, there'd be a 'JD' and then an eleven for the numerical value. Over time, you'd see a lot of repetition there.
Let's normalize this turkey. We create a new table called Card. We have fields for suit and card; each card in the deck has a record in this table. Notice that suit and card have been separated out so we don't have to do any more parsing. The only card description in HandCards then is a foreign key back to this Card table. To handle the numerical value of the face cards, we create a new table called CardValue with two columns: card (eg, 8 or J) and numerical value. It would be possible to put that data in the Card table, but the database wouldn't be normalized. This entire approach gives us the best of both worlds: we can abstract the way we determine our hands, and we do it without repeating a lot of data. After discovering this, you're completely within your rights to stand up on your desk and start dancing the robot.
If I were Doogie Howser, I probably would've seen this solution right away. However, it took me 3 tries to get it correct; not only am I not Doogie Howser, I'm not even Vinnie. Trivial problems don't always have trivial solutions, and it's something I forget constantly. The only way I can approach success is to take my time and review everything with a critical eye. No one ever said being Doogie Howser was easy.
For the past couple of months, I've been thinking a lot about exceptions. Not exceptions as in "I hate everyone on The View but Star Jones", but the erroneous/exceptional situations that arise when I run some of my programs. For instance, in Java, if I'm trying to compute an average and I inadvertently divide by 0, an ArithmeticException gets thrown. To abstract that situation, the exception is the object encapsulating that erroneous condition. Since they're objects, you can do a lot with them, and that makes exceptions very, very useful. So useful, in fact, that in my more fanciful moments, I've dreamed of making a pair of pants that could throw exceptions. "Uh oh, I've got to make a stop by the house; it seems the Levi's VM just raised a HoleInTheCrotch."
Sure, exceptions are useful, but how exactly do you make use of them? Once you're making use of them, how do you ensure you're doing it correctly? For that, I am here to investigate.
If you've ever looked at any Java or C# code, you've probably seen something like this:
Being big time, professional developers, when most of us write blocks of code, we're doing lots of stuff there. If an exceptional case does arise, it could be one of many different exceptions. Since these exceptions are different, you'd want to handle them differently. My pair of pants analogy illustrates this well. In addition to the HoleInCrotch exception, I'd also have a ZipperDown exception. Clearly, these are different cases, and they're corrected by doing different things. With one, I need to go home; with the other, I need to zip up. I can't just lump both together, because then I could either be going home to zip up my pants or attempting to zip the hole up. All of that, friends, is a balogna sandwich I don't care to eat.
If I want to address my wardrobe malfunctions appropriately, I need two separate catch statements like this:
Work on Piggybank, my investment manager app, continues to go pretty well. I'm in the actual programming now and I'm writing less about it because that part's not as interesting. I don't really see a raging discussion emerging from the way I calculate interest on a savings account. Maybe I'll do some next time on the general way I'm putting things together. If not, just imagine me hunched over my laptop, shovelling fritos into my mouth and cursing profusely. That's about as accurate a picture of the development process you're going to get.
The real reason I wanted to post today is because I wanted to give away a free product idea that would be pretty cool to implement. The idea sprung from a stor I read earlier this week, which told how the price of the keyword Celebrex has soared on both Google's AdWords and Overture, in light of some regulatory trouble. Immediately after reading that, I thought that someone should come up with a futures market for search terms.
Before anyone asks, no, a futures market isn't where you buy Biff's shoes from Back to the Future. Trust me, if a market like that existed, I wouldn't have any time for the internet. But really, a futures contract states that you'll buy or sell a certain asset at a certain price on a certain date. Futures are used to speculate about price changes for a good in the future, and to protect against any price fluctuations in the future. Usually it's for boring stuff like corn or soybeans, but the search terms would work just as well.
Here's how I see it working. I believe that lots of people will be searching for information about vienna sausages in the near future. I act on this belief by buying a futures contract for this term worth 100 referrals for January 2006; this contract costs me $100. A few months go by, and Puff Daddy is seen eating a can of vienna sausages with his Krystal. Suddenly, everyone is searching for vienna sausages, and the price of the keyword has gone shooting up. Holding this future's contract, I would start licking my chops and shopping for limos with built-in lobster tanks; I'm in the money!
At that point, I could sell my contract to someone else who thinks it's worth a lot of money; this represents the speculator's route. I could also hold onto my contract until January 2006, when the seller of the contract would have to give me those referrals, which I'd use to solidify my position as the kingpin of the vienna sausage industry. That path shows how futures can protect against price fluctuations. Either way, by investing in the futures contract, I've managed to bolster my income.
Futures are really, really interesting financial instruments, and it seems like they really apply to search terms, one of the most volatile assets around. There are a lot of hurdles to starting something like us up, though. It seems like it'd almost have to be a search company to act as pioneer here. If that's the case, then I urge these companies to go forth and conquer; all I ask in return for this idea is the first crack at the vienna sausage futures.
When I was an undergraduate, I did a semester-long research project with one of my alltime favorite professors, William Breit, on the efficient pricing of software products. (I'd advise anyone currently in college to do something similar; it was an insane amount of fun.) Joel recently posted an essay on this same subject. I respect Joel and I enjoy his work, so I read his new piece with particular interest to see if we came to any of the same conclusions. Well, we didn't. To me, Joel's essay was simplistic and scattered with regards to the economics it contained. In all fairness, my work is probably that of an incompetent bed wetter, but I thought I'd share my own thoughts on the subject anyway.
One of the fundamentals of Microeconomics is that a firm maximizes profit by setting output equal to the point where marginal cost equals marginal revenue. There are some fancy words there, but it's a pretty simple concept. As you make more of your product, each additional entity begins to cost a little bit more to produce. Maybe that's because you're using more electricity, paying overtime for your workers, or furnishing large amounts of booze to keep your employees from rioting.
Whatever the case, you certainly don't want to continue making products if the revenue you'll receive for selling that product is less than what it cost to make that product. If you disregard that, you'll soon find yourself tapdancing for nickels down by the subway and eating cold hot dogs for every meal. In other words, you'll be living like Corey Feldman. No one wants that.
The problem with software is, if you produce so that MC = MR, you could go out of business. That's because the majority of your costs in software are fixed. That is to say, most of the development and all of the planning occur before you sell anything. Joel referred to those costs as sunk, but I don't agree with that. Simply put, sunk costs are unavoidable, like a mortgage payment or the hush money paid to the garbage man who found the discriminating tape of you with the turkey baster. That's not the situation with a lot of development cost.
Hiring new people and buying fancy-pants software packages are discretionary; those compose the bulk of the costs for developing a software product. The costs are fixed in that they occur before production begins, but definitely not sunk since nothing compels you to incur those costs. (Uhhh, paging Mr. Powell, the Internet's Biggest Pedant award committee would like to speak with you...)
In order for the firm to succeed, some of those fixed costs have to be accounted in the price. The marginal costs (the cost of the CD the software's on, more support personnel, etc) are simply too miniscule to serve as the foundation for the price. That's completely contrary to the orthodoxy of microeconomics, but it's obvious after a moment of consideration. So what do you do? What's the formula? I don't know; my answer's no better than Joel's there. Let us all hope that, some day soon, some bright mind can contribute something there to save us all from Corey Feldmandom. Until then, we have to wing it.
Man, I wrote a ton yesterday here. And if you doubt that figure, I should inform you that I went down to the truck weighing station last night and put the last entry on one of the scales. It weighed exactly 2000 pounds. I could literally choke an elephant to death with my morbidly obese last entry. Of course, it's very improbable that I'll attempt that. You never know, though.
But anyway, due to the long post, this is going to be a really short entry. All I want to do is share an observation.
Lots of times, I hear people remark that Java and C# are practically the same language. "Aside from the libraries, it's all the same!" Similar, sure, but the same? THE SAME??! These jokers probably think that it's hard to tell Mary Kate and Ashley Olsen apart. Puh-lease. We all know Mary Kate is slightly more fragrant and bewitching than Ashley.
It'd been a while since I did any code in Java, so last night, I decided to reacquaint myself with it. And yeah, the languages are pretty similar. They're similar enough, in fact, that if I did all of my programming in a simple text editor, I'd have no problem switching between the two. I don't do that, though. I use an IDE with Intellisense when I'm coding (Visual Studio for C# and Eclipse for Java). Those environments are so dissimilar, I can't help but get frustrated sometimes when switching back and forth. All of a sudden, the menu options differ and none of my keystroke sequences work.
The languages are similar, but the development environments are not. For me, it's hard to separate the two, so switching between the languages provides a very confusing experience for me. The best way to get around this would be a skin for the IDE you could apply to make it appear and function like another IDE. That way, rogues like myself could switch between languages with impunity. To my knowledge, neither Eclipse nor Visual Studio offers this functionality. Until they do, I'm afraid I'm stuck in a world of Olsens.
Just a little post for right now, since I'm working on something larger for tomorrow. Patrick shared something with me today, related to the hugezilla databases we deal with at work.
Quoth the Lioi:
"Last night I wrote some UPDATES that took a total of 7 hours to run. I knew I was going to have to re-run them as I made some other changes to some other scripts. Instead of running the 7 hour long program, I took the result of yesterday’s run and created a lookup table, and then wrote the equivalent of the long-running UPDATES that used the lookup table instead of calling a function.The new ones take 10 seconds to run.
There must be a HUGE performance overhead when calling a UDF rather than using a subselect."
At work, we're getting started on a big rewrite of our main application. In all likelihood, this project will take several people at least a year to complete, as we have to rewrite everything for C# and SQL Server. To put it bluntly, it's time for us to put on our big boys pants and start struttin'.
The boss charged Patrick and I with doing a lot of the architecture work. That excited me; I've never done anything like that on this large of a scale. Also, it meant that the next time I got frustrated with the program structure, I would only have myself to punch in the face. Abuzz with enthusiasm, we hashed it out and talked it over for a few weeks. Finally, after several gajillion emails, we came to an agreement on just about everything. Having reached that point, it was now time to actually get started on the architecture documents to which the entire team would refer. We've got it all figured out, now all we need to do is put it down on paper. That should be the easy part, right? Well, allow me to channel my inner sassy lady and defiantly declare, "NUH UH, HONEY!"
I soon discovered it was nearly impossible to start the damn thing. Hard tasks are like that; there's so much to them, I find it difficult to determine where I should begin. That went on for weeks. Depression set in. I spent all of my time in my office, dressed in black, listening to the Cure. And then, in my darkest hour, my boss came through with a simple set of questions related to the architecture for me to resolve. Starting with those, I'm now back on track.
Here, roughly, are the questions he gave me.
1. Start with a simple physical architecture. How many tiers exist? Where do these tiers exist?
2. Expand the physical architecture into a logical architecture. What are the layers? How do the layers operate and interact with each other?
3. Describe the layers, with regards to encapulation, threads, etc.
Looking back now, I have an idea why these questions motivated me. The way he phrased them, it felt just like a test. The nerd in me knows how important tests are and how critical it is to finish tests in a timely manner, so once I began to think of documenting the architecture in such a fashion, I became much more productive.
The next time I get stuck on a task, I'm going to ask someone to do this for me: come up with a very general, open-ended set of questions that I can attack like a test in order to get me started. Yeah, it's sort of an odd request, but it's certainly preferrable to listening to me singing along to the Cure.
Way back when I was consumed with Cast/Convert fever (more contagious than Disco Fever, less harmful than Yellow Fever), I mentioned there was a difference between the built-in data types in C#. Some are reference types, and others are value types. Java has the same distinction with slightly different verbiage; it possesses reference types and primitive types. As the kids on the street say, what's the dealio?!
To the uninformed, reference type vs. value/primitive type may sound completely made up, like an explanation I'd use whenever someone discovered a crazy bug in my code. Outer voice: "Umm, maybe the method is expecting a ... reference type." Inner voice: "What the hell am I talking about?" But no, these terms actually mean something! And if we're going to be the highly-skilled code ninjas that our business cards purport us to be, we should be able to throw these terms around like nobody's business.
Really, if we just examine the terms, we can get a pretty good idea of what they mean. It may seem shocking, but a value type stores a value of that type. That's so easy, you could almost call it primitive (hey o!). Just to rock your world a little more, a reference type stores a reference that points to the value.
Now that we know the definitions, let's try to deduce what it means. If the value/primitive type is storing the actual value of the variable, then it's got to allocate a specific, appropriately-sized chunk of memory. Knowing that, it'd make sense value/primitive types be very narrowly defined, with a clear range of values. You know, kind of like an int, which is always 32 bits. By cracky, such well-defined numeric values are exactly what we store with a value/primitive type. It's just not numerics that are value/primitive types, but any variable with a specific size (byte, bool, char). It's easy for the compiler to know how much memory to allocate to these types, and it does so accordingly.
What about the sticky wickets? Some types don't have a set size; they possess variable length. Two examples here are strings and arrays. There are no well-defined limits to strings or arrays, they can be however large you'd like them to be plus you can change the size willy-nilly. With that in mind, wouldn't it be a lot more complicated to allocate the m emory for these types? As such, these types are reference types that simply contain pointers to their actual value. And it's not just strings and arrays that are reference types, but any type whose size isn't well-defined. So, classes, interfaces, and delegates are all reference types. If you're ever at a loss to whether something is value/primitive or reference, see if you can make an informed guess as to how large the data type is. If you can't, then it's probably a reference.
Enough with the gum flapping! What does all of this mean? Well, nothing earth shattering, but it adds a lot of wrinkles into coding. For example, a primitive can't hold a null value, while a reference type can. That makes sense: the value type is there to hold a value, while the reference type is merely there to point to something else. In conjunction with this, value types have default values that are filled in by default constructors called whenever you initialize them. Not so with a reference type. Simply put, there's always a value with a value type. If we don't code expecting that, then we could be visited by unpleasant surprises.
It should be no surprise to you that it gets a lot more complex than this. I'm all about keeping it simple here on the vlog though. I do it for two reasons. First, I'm not very intelligent. Second, some of us have better things to do than ramble on the Internet all day, such as catalogue our He-Man plate collection. It's a little complicated, all of this value/primitive/reference type stuff. It's not complicated enough that we should just use strings for everything, though. With some critical thinking and some good online resources, by the power of Greyskull, all of us have the power.
More Reading:
Java Data Types, C# Data Types
In case you need any further proof that I'm an idiot, I read the discussion groups at Joel on Software. Not that the people there are stupid, but online discussion groups in general are stupid, simply because 75% of the messages are "WTF???? YOU USE THE FRAGOMETER 4.27 TO SCRAMBULATE YOUR VECTORMANIONS???? USE 4.27b DUMBASS!!!!!!!!!!" Anyway. I was reading a thread today that was kind of interesting, about writing your apps in a simple scriping language, then writing a converter to translate that simple scripting code into a more robust language. From the first post, I gather that's what Joel's company did with their main product, doing their development in VBScript then converting that to PHP. There are a few advantages here.
1. By selecting an easy scripting language to do your development, you ought to be able to produce a lot of features relatively easily.
2. By translating your scripts to another language, you can accomodate a lot of different environments. If the masses all start running Python instead of PHP, bam, you just change your translator.
3. The people on your team, saving those who do the translator, only have to work in one language with a very easy learning curve. That should make it a lot easier to add new people.
All of these are valid points, yet I can't resist the urge to be a Negative Nancy. Reluctantly I must declare, "Let's scrambulate some vectormanions!"
It seems like for each of these advantages, there exists a disadvantage.
1. With a simple scripting language, you could do a lot of features, but I don't think you could do them well. Simply put, you have less tools at your disposal with which to implement features. As such, the choice is either to simplify the feature or to compensate for your language.
It's easiest to think of this in an analogy. Let's say you take two builders. One has an impressive collection of tools, while the other uses only a hammer and a saw. Which would you want to build a chair for you? I'm sure both could make a sure, but I bet the builder with lots of tools would produce a chair that's a little more refined, and he'd produce it a little bit quicker.
2. You can accomodate a lot of different languages and environments, but only to a shallow extent. That is to say, your production code will always be dumbed down to VBScript's level. You can't add quality or robustness through the translation process, not if it's abstracted. If it's not abstracted, why not just write it in the translated language to begin with?
3. It would be a lot easier to add new people, but can you imagine adding any good people if you only worked with VBScript? "Previously, I was on the team that helped write the OS for the space shuttle. Then, one day I realized I'd be a lot happier writing business apps in VBScript." Unless the CEO has some compromising photos of the developer with a french maid and a jello mold, I don't see that happening.
I've never tried this, so I can't say how effective it'd be. It's certainly an interesting idea, but it's one that would need some more evaluation before jumping right in. All I'm communicating here is that the idea isn't perfect. Now if you'll excuse me, I must go register my disgust with the Fragometer 4.27b.