This is Too Much

Okay blog spammers, you've officially crossed a line.  For years you have annoyed me with advertisements and for years I've just tolerated it.

Viagra? I'm sure my stuff won't work right when I'm old, fair enough.  Penis enlargement? What guy wouldn't want a bigger unit? Bigger boobs? Don't let me stand in the way of you expressing yourself. Weight loss supplements? Sure, I need to lose a few pounds.

But now, you have officially gone too far:

What the hell? There is nothing cool about yeast infections and I sure as hell don't want to see pictures. You are some sick bastards.  Is anyone really clicking on this crap?

Nixie Tube Clock

My wife got me an amazing gift for Christmas, a kit to build a nixie tube clock. I've been wanting one of these for years, but was unwilling to pay the high cost for an assembled one. The kits looked way too complicated and intimidated the hell out of me. Given that, I had come to accept that I would never own one until I had more money than sense.

Apparently my wife had way more faith in me than I do. I was shocked to open my gift and find this kit from tubeclock.com. The box included everything I needed to put the thing together: Printed Circuit Board(PCB), nixie tubes, chips, resistors, capacitors, diodes, etc. In spite of instructions which are very thorough, I was feeling less than confident. There was a lot of little parts that needed to be soldered onto the PCB and that's something I had never done.

The first thing I did was read the instructions cover to cover. The big scary disclaimer telling me that I was dealing with potentially lethal voltages didn't scare me, but the first dang step sure did. The first thing to be soldered onto the board is a tiny chip about the size of a dime with 44 leads coming off of it. *gulp* For the next couple of days I watched a handful of youtube videos showing how to solder components onto PCBs and decided to give it a go. If I could get past that first chip, then the rest of it would be easy.

Up to this point in my life, I had only soldered wires to other wires messing around with my truck. Take two wires, twist together, heat with my cheap soldering iron, add solder. The videos I watched revealed that my crappy iron with giant tip wouldn't cut it for this project. I spent another day researching soldering irons and stations. Not wanting to spend a ton on a soldering station to do a project I wasn't sure I could even do, I purchased this one along with the extra tips which seemed to have okay reviews.

The night my soldering iron came I got started with the hardest chip. The hardest part of this was getting it lined up with the leads on the PCB. It was really tiny and my big clumsy fingers kept bumping it off the leads.  I tacked it into place and made sure it was lined up just perfect.  I decided to follow the instructions and just bridge the connections and then use the copper wick to remove the excess. That worked well and things seemed to check out on the multimeter.

Ugly, but seems to work.

That was all for the night. When I woke up the next morning I was feeling empowered, so I got back to work.  The rest of the components have leads which go through the board and then you fill the hole with solder.  This was MUCH easier than the chip above.

Getting Started

I stopped for a few hours and took care of some stuff that actually needed doing and then got back at it.  The rest of it pretty much fell together.

Almost done, tubes are on (backside).

Tubes are attached.

The next step is to attach the power cord and test it before stuffing it all in the case. I was expecting to have to troubleshoot, but it worked first time!

Success!

Finally, all that had to be done was to put it all together in the case.  This proved to be more challenging than most of the soldering.  I ended up having to file the holes where the nixie tubes pass through to get it to fit.

Done

I'm fairly proud of myself for doing this. I'm not sure this was an ideal project to learn to solder on, but it turned out okay I think.  I'm sure those of you who actually know how to do this stuff have some criticism for my soldering job. I'm just happy that I didn't electrocute myself, didn't burn a hole through the PCB and didn't catch anything on fire. Now I have a sweet glowing clock.

State of the Masked Input Plugin

This post should be titled, "Dude, Where the Hell have You Been?" I'm sorry I have ignored this project for so long.

New Home
First, let me get started by saying that I moved the source to github a while back.  It now lives here. If you look at the commit history, I moved it there months ago, fixed a few outstanding bugs, added a feature that someone needed for a specific project and then just left it. I'm picking it back up somewhat, but we'll talk about that in a minute.

Email Bankruptcy
There have been a TON of emails from you guys; so many that I haven't been able to keep up.  Most of the emails have been about two bugs: an off by one goof I made for the completed function and forgetting to use charAt() to access a char in a string. These bugs are fixed in the github repo right now (I think). I'm calling my email situation a total loss.  Sorry to those that have emailed me and not gotten a response.

Birth of a New Project
Part of the reason I stalled on this project was a lack of tests.  For a while I wasn't sure how to even test this thing given that it is purely driven from user input.  Up to this point I had just been opening up a test page in every browser I could think of and running through a few things manually.  A couple of weeks ago I sat down one night and spiked out a rough version of a keystroke simulator which I'm now calling KeyMasher. Please be kind, it's still very rough. Once I get it more polished, I'll put up an official project page on my blog here.  I had found a few other projects which do this and jquery.autotype seemed to be the closest fit. Unfortunately I couldn't get it to work with my specific needs, so I've now written my own with a syntax I feel more comfortable with.  I've already worked out a few tests using this against my masked input plugin.

I'm Just One Guy
After I get a half way acceptable set of tests around it, then I can feel a bit more confident about what I change.  I would like to be able to implement some of the features I've seen come across my email. It will take some time to get everything to a place where it should have already been.  Please be patient, I'll get there. :)

Be Proud

The other day I called up a former co-worker to share an epiphany I was having. "Hey dude, I just wanted to call and tell you that you should be proud of what we managed to accomplish where we worked."

Courtesy of NeoGaboX

At the time I was pretty down on myself. I helped implement a system from the ground up which grew in a very organic manner. The thing it ended up being was not what we intended to write in the beginning. Web services talked to other web services in a chained together fashion. We only had one database instance where data loading, exporting and reporting all competed for resources. The applications were all coupled to an awkward schema and changes to it required changes to everything. I basically considered it a complete disaster and felt really crappy for having been a large part of its creation.

What a difference half a year can make. I've been exposed to some gnarly stuff both good and bad. The good stuff? Well it's better than most of the stuff I wrote. The bad stuff? Oh man, it stinks. It stinks in ways way I can't even describe, but I'll try my best:

Awkward schema?
The horribleness I created pales in comparison to what I've seen. I got to see a schema which was produced by a vendor which decided it would be awesome to obfuscate the schema by naming tables and columns with 3 letters and 5 digits. It was then picked up by a vendor which decided to add it's own tables and columns filled with inconsistencies. These were easily identified with vanity prefixes. Foreign Keys? Those are for suckers.

Applications coupled to one another via the database?
Oh yeah, I've seen worse there too. Except this time the schemas are bigger. Keys are repeated in places that seem to not need to be repeated. Columns are foreign keys to other tables with names that don't match up. Rogue applications are writing data in ways which break other applications because they forget to update denormalized fields or just omit data entirely. Sometimes they forget to update fields which hold similar data but in different ways. How many fields indicate status for a record in your app? Less than 5? Pffft, you must be doing something wrong.

Chained together applications?
I thought that chaining together services was bad enough. At least those had some form of a contract to communicate between one another. How about applications that are chained via batch job AND are coupled to the database? Run one process and it inserts into a table, run the next process and it processes those records. The 3rd one cleans up after the first two. If something breaks in the middle, may God be with you if you attempt to just re-run the process without cleaning up.

Looking back...
I would have loved to have had the resources to have multiple database instances. I mean, we were developing directly against the production environment. That's like running on a tight rope with no net while holding really sharp knives with your ass on fire. How the heck I never screwed something up in a catastrophic manner, I'll never know. I must have digital guardian angels.

This is when I started to get a warm mushy feeling about what we accomplished. We didn't have reporting databases (that would have been awesome though). We didn't have readonly copies for ad-hoc queries (that would have been awesome too). Nope, we had ONE database and we had a lot of junk coming in and we managed to produce a relatively clean stream of data going out. Here's the amazing part to me: we were handling a lot higher volume of data than these other systems I've been exposed to since. That gives me hope that I'm doing SOMETHING right.

Does it mean we are awesome software developers? Nope. We just did whatever we had to do to get the job done. We had limited resources and we made it happen by using whatever tricks we could find. It was all trial and error. Ultimately I'd say it was more expensive for our employer than if we had what we needed. Looking back, we could have added so much more technical value to the company instead of figuring out how to optimize every single process to run on one machine.

I think I figured out all of the wrong ways to write code. I screwed up a lot of stuff, but it was all fixable. Because of the amount of ridiculous optimization we had to do, it looks like we got quite a bit right the 2nd (sometimes 3rd) time around. Sure some of it was messy, but it isn't near as bad as some of the stuff I've seen since. If I had it to do all over again now, I would have done things quite differently. That's par for the course being a software developer though. We're constantly learning new ways to do what we've already done in a better/faster way. Going forward, I will not let current advancements affect how I perceive past accomplishments. I shipped a lot of software that works. I'm proud of that.

Bug Recipe: Double Duty View and a Misguided Property Name

At work I've picked up an existing project and have been adding features to it. This has been a whole new thing for me since most of the stuff I've worked on in the past has been projects of my own creation. I recently got caught with my pants down when I let a bug slip over to the QA people. I got bitten because I trusted that a property name did what it said it did and because I didn't thoroughly test the possible scenarios around this particular feature. It's my fault for letting this by, but I just wanted to highlight how important naming really is.

It all started with a simple user story: User would like to track the expiration date of bacon.

Simple enough, I opened up the view model and added my ExpirationDate property.

    public class BaconViewModel {

        [Required]
        public virtual string Name { get; set; }

        [Required]
        public virtual DateTime? ExpirationDate { get; set; }

        // A lot more code here....

        public bool IsNew{
            get { return String.IsNullOrEmpty(Name); }
        }
    }

Up to this point, creating bacon really only had one property to fill out, the Name. What I failed to notice was that little devil of code in the IsNew property. Does a view model not having anything in the name really make it new? I'm getting a bit ahead of myself though, so ponder on that last question while I continue to tell my story.

The IsNew property itself isn't the only ingredient to this bug. The other part stems from the fact that in the project I inherited, the view does double duty for create and edit. Here's the basic view code before I added my feature:

    <h2>
        <% if(Model.IsNew) %>
            Creating Bacon is the most noble of all tasks.
        <% else %>
            Be careful editing bacon.
    </h2>

    <% using (Html.BeginForm()) {%>
        <%: Html.ValidationSummary(true) %>

        <fieldset>
            <legend>Fields</legend>

            <div class="editor-label">
                <%: Html.LabelFor(model => model.Name) %>
            </div>
            <div class="editor-field">
                <%: Html.TextBoxFor(model => model.Name) %>
                <%: Html.ValidationMessageFor(model => model.Name) %>
            </div>

            <p>
                <input type="submit" value="Sizzle" />
            </p>
        </fieldset>

    <% } %>

Of course this is all just a contrived example, but do you see that bit of code in the h2 tag? If we're creating bacon we want to show one thing and if we are editing then we want to show another. I went about my business and added the UI code to capture that bacon expiration date. When I did all of this I introduced a nice little bug.

What happens when I'm creating bacon and give it a name, but fail to give it a good expiration date? The post happens like normal and a partial view model gets filled out and the ModelState has errors. We throw that partially completed view model back to the view along with the errors so that the user can weep at their awfulness. Except this time that IsNew property isn't feeling so new anymore and now the view goes into edit mode and thoroughly confuses the user. Witness the carnage:

Like I said above, this is a contrived example. What really happened in my case was an exception when I tried to grab the value of the nullable property. Hopefully I've made my point though. The two lessons I'm taking from this experience is:

  1. Don't have views that do double duty. If you have parts that are the same, you can use partials to keep things DRY.
  2. Make sure that your property names do what they say they do all of the time and not only just out of coincidence.

No small animals got killed because of this bug obviously, but I did take a nice punch to the ego when QA found a fat bug due to an enhancement I made. That will just be one more thing I know to check when I'm spelunking in other people's code. Happy coding!

« Previous PageNext Page »