Complaining Works

Posted 2/7/2010 7:46:35 PM

Several months ago, I called my bank to complain about an issue I had with their website. It's a minor issue that goes like this:

When you first navigate to the website, keyboard focus goes to the Username textbox. That is to say, a Javascript script runs that moves keyboard focus to that textbox. The downside to that is, some users (i.e. me) are so fast that by the time the page finishes loading, we've clicked the username textbox, filled it in, hit TAB, and started typing in the password. This introduces a race condition whereas the user is racing against the page load complete event.

The page finishes loading sometime while the password is being entered and Javascript pops keyboard focus back to the Username textbox while the user is in the middle of typing their password. Thusly part of the password ends up in the Username textbox, which is not masked. This is a security issue, but moreover it's downright annoying as the user now has to retype both text values.

So I called them up and offered a simple solution: Check to ensure the Password textbox is not currently focused prior to changing keyboard focus to the Username textbox.

Months later, looks like they fixed the issue - just not the way I intended. I load up the website and keyboard focus goes straight to the username textbox, prior to the page load finishing. I guess they changed the script to run when the textbox loads instead of when the page finishes loading. Good enough for me.

I suppose it's possible that my internet connection is simply faster at my new apartment, though speed tests indicate otherwise. Another possibility is that the bank upgraded or fixed a performance problem, thus the script ran faster than I could click on the username textbox. Honestly I'm too lazy to check. Either way, they fixed the problem.

The lesson: Complaining gets things done.

VB.NET vs C# - If/Then/Else Syntax

Posted 2/5/2010 5:14:34 PM

Does VB.NET's if-then-else syntax bother the crap out of anyone else out there?

  1.         If isCondition AndAlso isOtherCondition Then

  2.             DoSomething()

  3.         ElseIf isCondition Then

  4.             DoSomethingElse()

  5.         ElseIf isOtherCondition Then

  6.             DoSomethingElseElse()

  7.         End If

  8.  



Wow, that's verbose and wasteful for a simple operation like that, don't ya think? Fortunately, VB.NET still carries over the : operator from the decades of yore, and we can abbreviate it thusly:

  1.         If isCondition AndAlso isOtherCondition Then

  2.             DoSomething()

  3.         ElseIf isCondition Then : DoSomethingElse()

  4.         ElseIf isOtherCondition Then : DoSomethingElseElse() : End If

  5.  



Still needs work. Just for comparison, let's see what this is like in C#:

  1.         if (isCondition && isOtherCondition) DoSomething();

  2.         else if (isCondition) DoSomethingElse();

  3.         else if (isOtherCondition) DoSomethingElseElse();

  4.  



Aaaaahhhhhh, that's better.

And don't even get me started on the ?? and ?: operators. Come on VB, you need these things!

Extension Methods and Syntax Semantics

Posted 1/30/2010 12:46:19 PM

If we have Extension methods:


public static TimeSpan Days(this int input) { return TimeSpan.FromDays(input); }

public static DateTime Ago(this TimeSpan input) { return (DateTime.Now - input); }



Then we can:


DateTime when = 24.Days().Ago();



Pretty neat, huh?

On Measurement of Wind Travel

Posted 1/28/2010 10:28:40 PM

Doesn't it bother anyone that wind is the only thing whose direction we measure in reverse? That is to say, we express the direction it's coming from rather than the direction in which it's moving.

Think of all the things whose direction we measure in the direction of travel: Traffic, water currents, and so many other things. You don't say "I'm coming in from the South", you say "I'm heading North".

Then there are the different names we give things. For example, Gale Force Winds are considered to be strong, but range from 31 to 63 MPH. By the technical definition (Beaufort Scale), we experience Gale Force Winds every time a truck passes us on the freeway, or even on a moderately windy day. Winds from 64 MPH and up can be referred to as a Hurricane, Very Severe / Super Cyclonic Storm, Tropical Cyclone, or a Typhoon. The actual name depends on where the wind is, which seems like an entirely arbitrary distinction.

All I'm asking for is a little standardization. How hard can that be?

VS2010: Test Results and Code Coverage

Posted 1/20/2010 10:17:28 PM

When I started playing with Visual Studio 2008, I liked the Tests feature, which enabled me to write unit tests from within the IDE. Finally I didn't need NUnit or any of those other third-party tools. I don't like third parties. However, I never really saw the advantage in tests until my stint at A Major Insurance Provider, which was all about Enterprise practices and what-not. They showed me how they do their tests and over time, I began to like the idea. MV6 even had 150 unit tests.

Recently I discovered the Code Coverage feature of Visual Studio 2010. For every overload of every method of every class, it tells me what percent of my code is covered by my tests. Here I was thinking I was finally doing the right thing and being all Enterprisey, and along comes another analysis feature I never considered. So I ran it against my new KC Architecture and the results were disappointing.

I thought I had pretty decent code coverage, but the results say otherwise. Almost all of my constructors and destructors had 0% coverage; along with a bunch of helper methods. Luckily, this gave me an opportunity to revisit my initial design and I realized alot of things could be static, thus obsoleting the constructors and destructors entirely. Obviously, none of my UI Event Handlers had coverage. Who thinks about unit tests on the presentation layer?

Even on my Business layer, where most of my logics live, I found tons of cases I hadn't considered tests for. For example, my error logger has four Write() overloads, and I only had tests for one of them. Even then, I only had tests for a couple of execution paths. Additionally, I've been using the Visual Studio Code Analysis feature, which tells me to validate parameters prior to using them; and I hadn't written any tests that involved testing for null or other invalid parameters. VS2010 actually accounts for these items. So much more useful than the VS2005 most .NET shops are using.

So I sat down and started adding Tests. Before I knew it, I had doubled the number of tests in the KC Architecture. Of course, I tend to throw many scenarios into a single test and debug issues with the message overload (i.e. Assert.IsTrue(result, "Failed on record "+i.ToString());); but I'm sure I could easily double or even triple the number again by breaking the tests into more discrete tests like the real Enterprisey people do.

I'm learning. I'm still a code cowboy; but I'm moving into more of an Enterprise mindset. Slowly but surely. I honestly don't see why we have to be Enterprisey Developers to build Enterprisey products. I was once told that I delivered more than an Enterprisey College Graduate delivered in a whole year. I like being the guy that does that.

MV7 is Online

Posted 1/19/2010 10:00:00 PM

Newest version of the blog (Codename: MV7) is now online. I figured it was "done enough" to launch.



Of course there are still some nagging issues (i.e. the "About" page is still blank and there is no Comment functionality yet), but overall it's working. The new look and feel seems more intuitive, and I threw in a Gallery page for the hell of it. It's really just a TreeView and an image, but it seemed like something I should have a central place for. Expect me to add my "Stuff to show off to everyone" here.



The new blog is part of my new KC Architecture, a 3-Tier Application framework I've been working on in .NET 4.0 and Visual Studio 2010. Rather than bother with Windows Live ID authentication and a whole admin section like I had in MV6, this time I'm working on a CMS WinForm that will handle the management tasks locally. If I want to blog from far away places, I can still remote desktop in :)



Ugh, since I let zi255.com expire and all my image tags pointed to that domain, I'll have to go back and do a huge search and replace... Across 676 posts... But I have to check each one because I mention zi255 in places other than img tags... sigh...

C# 4.0: Complex String Duplicate Filter using Dynamic Typing

Posted 11/17/2009 3:40:19 AM

I've been messing around with the dynamic typing features in C# 4.0. It took a little while before I actually came up with a good use for them, but I finally found one.

I had a situation that seemed like it should have a small custom class with two properties: A string and an int, representing the number of hits of that string within a List<string>.

That seemed like overkill. Best practices tell me this puny little class would expect its own .cs file, and I just wasn't ready to write a whole .cs file for two variables. I may be leaning toward the whole Enterprise Architecture mentality, but not that much :)

I tried a Dictionary<string,int>, but that didn't work as it doesn't provide an iterator.

So I have a problem whereas I want to create a complex duplicate filter based on a List<string>. Well, not really a duplicate filter so much as a "nearly duplicate" filter. That is, I want to remove any instances from the list if they contain a word that occurs in multiple items in the List, except short and common words. Oh sure, it sounds simple. But I wanted to do it a new way.

At first I thought I might be able to use anonymous types and stick them into a list of their own type.


List <(new { Word = "", Instances = 0 }).GetType()> words2 =
  new List<(new { Word = "", Instances = 0 }).GetType()>();



Obviously, that didn't work. I got tons of compiler errors like Using the generic type 'System.Collections.Generic.List<T>' requires 1 type arguments and Argument 1: Cannot convert from 'AnonymousType#1' to 'int'. But I was passing in a Type... bah, that's not going to work.

My figuring is that I just ran into a contravariance issue whereas the compiler tried to find the most suitable overload for the List<type> constructor and thought List<int> was the closest match, possibly because my anonymous type had an int property and the int constructor comes before the string constructor in the framework assembly.

What I needed was a way to force it to use the List<object> constructor without having to box the variable. Why avoid boxing? While object is the only type you can cast an anonymous type to, for some reason they don't like being cast back from objects into anonymous types, so unboxing would have been impossible.

So then I remembered I was working in .NET 4.0, and thus I could use the new dynamic keyword as a type. That made it simpler. I'd still use anonymous types, but the anonymous type itself would be the dynamic type in my Generic. Dynamic directly extends object, so the compiler should see that constructor overload first and go directly there based on base class inferrence.

My brain goes into recursion just thinking about how this resolves at runtime :)


private static List<string> ComplexDuplicateFilter(List<string> input)
{
 if (input == null || input.Count == 0)
  return input;
 input = input.Distinct().ToList();

 // Build a list of words and how many times they occur in the overall list
 List<dynamic> words2 = new List<dynamic>();
 foreach (string line in input)
  foreach (string word in line.Split(new char[] { ' ', ',', ';', '\\', '/', ':', '\r', '\n' }))
  {
   if (string.IsNullOrEmpty(word))
    continue;
   else if (ExistsInList(word, words2))
   foreach (dynamic dyn in words2)
    {
     if (dyn.Word == word)
      dyn.Instances++;
    }
   else words2.Add(new { Word = word, Instances = 0 });
  }

// Remove extraneous entries for common word permutations
 List<string> output = new List<string>();
 foreach (dynamic dyn in words2)
  if ((dyn.Iterations > 5 && !output.Contains(dyn.Word)) ||
   dyn.Iterations <= 5)
    output.Add(dyn.Word);

 return output;
}

private static bool ExistsInList(string word, List<dynamic> words)
{
 foreach (dynamic dyn in words)
  if (dyn.Word == word)
   return true;
 return false;
}



Of course then I realized a couple of problems:
  • When you declare an anonymous type variable, its properties are read-only for some reason. Rather than changing their properties, one must instead overwrite them with a new anonymous type of the same signature (but with a different value per requirements).
  • CA1502: Method has a cyclomatic complexity of 33. Microsoft recommends it be <= 25. That is, the method has 33 different execution paths. Spiffy, I never knew that.
  • This method will be used to suggest SearchStatuses (i.e. tracked Google queries and commensurate ranks) in the Daily Report I'll get from META. Search engine queries tend to have quotes. D'oh! Easy fix, added another char to the string.Split argument.
  • A couple minor changes here and there... Obviously Instances would start at 1 instead of 0, etc.
I'm pretty satisfied with the final result:


  private static List<string> FilterByDuplicateWords(List<string> input)
  {
   if (input == null || input.Count == 0)
    return input;
   input = input.Distinct().ToList();

   // Build a list of words and how many times they occur in the overall list
   List<dynamic> words2 = new List<object>();
   foreach (string line in input)
    foreach (string word in line.Split(new char[] { ' ', ',', ';', '\\', '/', ':', '\"', '\r', '\n', '.' }))
    {
     if (string.IsNullOrEmpty(word))
      continue;
     else if (ExistsInList(word, words2))
      for (int i=words2.Count - 1; i >= 0; i--)
      {
       if (words2[i].Word == word)
        words2[i] = new { Word = words2[i].Word, Instances = words2[i].Instances + 1};
      }
     else words2.Add(new { Word = word, Instances = 1 });
    }

   // Remove extraneous entries for common word permutations
   List<string> output = new List<string>();
   foreach (string line in input)
   {
    int Dupes = 0;
    foreach (string word in line.Split(new char[] { ' ', ',', ';', '\\', '/', ':', '\"', '\r', '\n', '.' })
     .Where(p => p.Length > 7)
     .Distinct())
    {
     int Instances = 0;
     foreach (dynamic dyn in words2)
      if (word == dyn.Word)
      {
       Instances = dyn.Instances;
       if (Instances > 1)
        Dupes++;
       break;
      }
    }
    if (Dupes == 0)
     output.Add(line);
   }
   return output;
  }

  private static bool ExistsInList(string word, List<dynamic> words)
  {
   foreach (dynamic dyn in words)
    if (dyn.Word == word)
     return true;
   return false;
  }



So this solved the items on my issue list (bulleted above), and even resolved the cyclomatic complexity issue by accident.

Notice I'm also becoming more comfortable with lambda expressions and functions. They're big and scary before you figure them out, but once you do, you wonder how you ever lived without them.

Now I just need to find a good use for yield return and I'll be set.

Domains Expiring

Posted 11/9/2009 3:48:05 PM

A couple of my domains will be expiring soon, and I don't think I'm going to bother renewing them.

These domains will be expiring soon:
  • zi255.com - blog website
  • zindex255.com - blog website (dupe)
These domains aren't expiring soon but I probably won't bother renewing them when they come up:
  • damnednice.com - Name wasn't as "cool" as I thought it was when I bought it
  • multimononline.com - Dupe of Manymon.com; doesn't work with Windows Live ID
  • googlejuicer.com - Another one of my great ideas that I didn't bother doing anything with. Was going to be an SEO service.
So, going forward, these are the only domains I plan to keep and make use of:
  • kconnolly.net - portfolio and blog (public-friendly)
  • manymon.com - multi-monitor enthusiast site. Still plan to do this someday :)
I'm not planning to cancel them; just let them expire naturally. Anyone wanna buy some of these domain names before the domain farmers gobble them up?

Keep in mind, in addition to buying a domain, you still have to renew it. If I get a good offer, I'll sell it off early (i.e. Googlejuicer is a great name for an SEO service).

Expiration dates:
  • damnednice.com: 12/12/2011
  • googlejuicer.com: 01/01/2012
  • multimononline.com: 07/12/2010
  • zi255.com: 11/25/2009
  • zindex255.com: 11/25/2009
I've turned off automatic renewal on these domains. The other domains (which I'm keeping) don't expire for a couple years.

Anyhow, I'll be taking them all offline for the big move sometime around Nov 20-30th and will remain offline for a still-unknown timeframe. When the blog goes back up at kconnolly.net, I plan to have a shiny new interface - version 7. Why not, I have free time now.

Incidentally, if anyone is using one of these domains to send me E-mail (i.e. kevin@zi255.com), these addresses will become defunct when the domains expire. I suggest you use kevin@kconnolly.net - I plan to keep that domain for a long time.




Evil Update Processes

Posted 11/3/2009 10:54:47 AM

I'm just about sick of the way applications traditionally update themselves.

Every fairly-savvy computer user who's ever installed an app like Java or anything from Adobe is aware of this by now. The app will insist on updating itself as soon as possible, usually by calling home every day or so.

Usually this has been done by installing an applet that runs at startup and keeps running as long as the computer is running. As a result, you end up with all kinds of useless AdobeUpdaters and GoogleUpdaters.

Some of us have let them live; some of us have killed them manually when we see them; but the paranoid and savvy among us generally disable them altogether.

Surely you'll recognize this screen:

Evil updates via task scheduler

See all that crap that was loading at startup? Google, Steam, etc. Only Google is an updater in this case (Though I disable crap I don't need anyway). I don't have Adobe Reader installed or you'd see them in the list as well; and I'm fairly certain I've seen Adobe Flash in here at some point. You'll probably never see a Sun/Java product installed on one of my systems ever again.

I've always checked here, in the registry under Windows/CurrentVersion/Run, and in the Startup folder in the Start Menu. Today I discovered another place they live, and it explains how things have been hiding from me.

Evil updates via task scheduler

The Windows Task Scheduler? Great. Google, you don't need to check for updates every fucking hour.

There is another way: Paint.NET checks for updates when you load it, and this option can be disabled. You can install the update now, when you exit the app, or never. This way is less annoying, but we can still do better.

I propose this: Windows/Microsoft Update should be extended to allow updates for non-Microsoft products. They already do this for driver updates, so why not extend this functionality to trusted partners like Google and Adobe? Even other parts of Microsoft?

I have no problem with Adobe and Google checking for updates; but they don't need a seperate update checker for every app/company, and they don't need to check 24 times a day.

Windows Update lets me set the schedule and inspect updates before installing them. It lets me do all this from one central place. This should be the accepted standard paradigm, and all updates should be done from one place. When this happens someday, I will allow useless updates to my PDF reader and flash player. Until then, you're out of luck.


Song: Code Monkey

Posted 11/1/2009 5:23:33 AM

Via Stanford course cs106x blog:



YouTube link

Lyrics:

Code Monkey
by Jonathan Coulton

Code Monkey get up, get coffee
Code Monkey go to job
Code Monkey have boring meeting
With boring manager Rob

Rob say Code Monkey very diligent
But his output stink
His code not functional or elegant
What do Code Monkey think?

Code Monkey think maybe manager want to write goddamn login page himself
Code Monkey not say it out loud
Code Monkey not crazy, just proud

Code Monkey like Fritos
Code Monkey like Tab and Mountain Dew
Code Monkey very simple man
Big, warm, fuzzy, secret heart
Code Monkey like you
Code Monkey like you

Code Monkey hang around at front desk
Tell you sweater look nice
Code Monkey offer buy you soda
Bring you cup, bring you ice

You say no thank you for the soda, cuz
Soda make you fat
Anyway you busy with the telephone
No time for chat

Code Monkey have long walk back to cubicle
He sit down pretend to work
Code Monkey not thinking so straight
Code Monkey not feeling so great

Code Monkey like Fritos
Code Monkey like Tab and Mountain Dew
Code Monkey very simple man
Big, warm, fuzzy, secret heart
Code Monkey like you
Code Monkey like you... a lot

Code Monkey have every reason
To get out this place
Code Monkey just keep on working
See a soft pretty face

Much rather wake up eat a coffee cake
Take bath, take nap
This job fulfilling in creative way
Such a load of crap

Code Monkey think some day he have everything, even pretty girl like you
Code Monkey just waiting for now
Code Monkey say someday, somehow...

Code Monkey like Fritos
Code Monkey like Tab and Mountain Dew
Code Monkey very simple man
Big, warm, fuzzy, secret heart
Code Monkey like you
Code Monkey like you

< Older