Wednesday, January 26, 2011

Telephone Game for Android

Chinese Whispers Promo ImageYou may know it as Grapevine, Gossip, or the Telephone Game; we call it Chinese Whispers. No matter what you call it, this is a new take on the classic game and we hope you enjoy playing it as much as we enjoyed making it for you.

You start the game with a short story and pass it to a friend. The next player illustrates the story with our built in finger painting canvas and passes it to the next player who will provide a new caption. Several rounds later, hilarity ensues!

We hope you'll check the Android Market for the free Telephone Game for Android by Mobile Magic Developers.

WTF is WTF Ware?

Wtf Ware LogoJames and I worked together for about 3 years at Emerald Software Group. James went off to ThoughtWorks and I stuck with Emerald. We've both spent most of our careers writing business applications.

While we love leaving a big project knowing we've made a difference, we got to wondering how we could write software that enriches the lives of more people. We decided we'd get together and start writing mobile apps that are entertaining, useful, funny, amusing, and enriching.

We started writing apps on our own and have had a lot of fun doing it. We decided that we ought to join our efforts and see what we came up with. Thus, WTF Ware was born.

I wish I could say we had a good story for how the name came to be or at least something clever WTF Ware could stand for. Unfortunately, no such story exists.

We were just about to start writing our first app and we realized we needed some sort of organization name. James asked, "WTF is our company name?"

"Beats me dude. Just make something up for now and we'll come up with something later."

Well, WTF Ware is what James made up and it stuck. So, without further ado, I'd like to introduce ourselves. We're wtfware.com and thanks for checking out our applications.

Monday, January 24, 2011

Upgrade Chuck Norris Facts Free

Chuck Norris Facts WidgetInitially, when I released Chuck Norris Facts, I published two versions. I had a free version which was limited in facts and functionality. Then I published a paid version that included all the facts and customization.

This proved difficult to maintain, so I decided to make the free version ad supported and (at the time of writing) fully functional. Unfortunately, it was still a little difficult to maintain. I still wanted to have only one code base so that I could release one app all the time. Another issue was that if you have the free version for a while and switch to the paid version, you lose your fact history and start over.

Thus, I switched upgrade paths. Now, I encourage everyone to try the Free Chuck Norris Fact Widget for a while until you decide that you like it. Then, you can purchase the Chuck Norris Fact Widget Upgrade for less than a buck. This will remove the ads immediately and you won't lose your current fact history.

If you are a user who has already installed the full Chuck Norris Fact Widget, you can download and install the free version and there will be no ads (as long as you don't delete the paid version). You'll have to start over with your facts (but they're random anyhow so it shouldn't be too bad). This way you'll continue getting updates with new facts and seasonal backgrounds.

If you really want to delete the previous paid version, send an email to me and I'm mail you a buck or something so you can download the paid key.

I'd also like to thank all of the users of both the free and paid versions for sticking with me through this learning experience. I hope it's been as enjoyable to use as it has been to write.

Sincerely,
Patrick Caldwell

Thursday, January 6, 2011

Chuck Norris Facts Widget for Android

Chuck Norris Facts WidgetA few weeks ago, I decided I'd like to try my hand at writing an Android application. One of my favorite features of Android over iOS (other than the fact that I think Apple lacks any form of ethics or sense of social responsibility) is that Android allows you to add widgets to your home screens. Sure, you can still have the half dozen views full of rows of boring icons, but the widgets give you a great deal of functionality without ever having to launch an app.

I decided a good first shot at Android development would be to write a Chuck Norris Fact of the Day widget my family and friends could stick on their home screens and enjoy a little daily pick-me-up. I knew that adding customizability would let me work with preferences and the nature of a daily fact would give me some Android data management experience.

I released the Chuck Norris Fact Widget on the Android Market and several of my family and friends downloaded it the first day. Over the next few weeks, about 1,500 of their family and friends downloaded it, so I've been working to improve it ever since.

If you're on your Android device now, you can download the free version called, Chuck Norris Facts Free or for just a buck, you can get the paid version called, Chuck Norris Facts with Widget. The icon should look familiar from above and the publisher name is, of course, D. Patrick Caldwell.

I hope you check it out and I hope you enjoy a little bit of my sense of humor.

Sincerely,
Patrick Caldwell

For the programmers who read my blog, I'll be posting some technical information I learned while developing this application. Specifically, how I managed to change the background image of my widget with remote views.

Tuesday, November 16, 2010

Improved UpTo Extension Method

RubyBack in May of '09, I wrote a post about an extension method to mimic Ruby's upto.

Today, I was hanging out at Visual Studio Live and had another idea. In Ruby, the upto method takes an end value and executes a code block. In C#, interpreted this as an extension method that takes an end value and an action. They syntax ends up being pretty similar and it works fine.

Lately, I've been using an Each extension method for IEnumerables. I know an Each extension method seems like a waste, but I like the fluency of it for basic actions. So, given that I have the Each method on IEnumerable<T> anyway, I decided UpTo should really return an IEnumerable as well.

Here's my new UpTo extension method:
public static IEnumerable<int> UpTo(this int start, int end)
{
    while (start <= end)
        yield return start++;
}
Now, instead of passing your action to the UpTo method like Ruby's upto, you get your enumerable and pass your delegate to your Each extension method. Here's what it looks like:
static void Main()
{
    //for (int i = 5; i <= 10; i++)
    //{
    //    Console.WriteLine(i);
    //}

    5.UpTo(10).Each(Console.WriteLine);
    
    Console.ReadLine();

    // output
    // 5
    // 6
    // 7
    // 8
    // 9
    // 10
}
If you're using .Net 3.5 or newer, Linq shipped with an Enumerator class which has a Range static method so your code could look more like this:
public static class NumericExtensions
{
    public static IEnumerable<int> UpTo(this int start, int end)
    {
        return Enumerable.Range(start, end - start + 1);
    }
}

class Program
{
    static void Main()
    {
        //foreach (var i in Enumerable.Range(5, 6))
        //{
        //    Console.WriteLine(i);
        //}

        5.UpTo(10).Each(Console.WriteLine);
        
        Console.ReadLine();

        // output
        // 5
        // 6
        // 7
        // 8
        // 9
        // 10
    }
}
Another reason to make UpTo return an IEnumerable instead of making it a void action executer is because sometimes you don't really want to pass a large anonymous method to the Each method. You can use the same UpTo method like this:
static void Main()
{
    //foreach (var i in Enumerable.Range(5, 6))
    //{
    //    // Do a lot of stuff!!
    //}

    //5.UpTo(10).Each(i =>
    //    {
    //        // Do a lot of stuff!!
    //    });

    foreach (var i in 5.UpTo(10))
    {
        // Do a lot of stuff!!
    }
}

Thursday, October 28, 2010

Results of the "What Really Makes a Good Programmer" Survey

Survey Response CountsBack in September I wrote a blog post called What Really Makes a Good Programmer? My goal was to ask various members of the development community what traits they thought contributed to the quality of a programmer. If you haven't taken the survey yet, I'd recommend you do that before reading the results. Wouldn't want to bias your opinions, right?

If you have taken the survey, but haven't told everyone you know to take it too, go ahead and do that; I'll wait.

Now that we've covered that, let's get on to the analysis. As you recall from taking the survey, there were 17 traits and you rated them on a scale of Very Important, Important, A little Important, Negligible, and Completely Unimportant. In order to do any analysis, I had to take these ratings and convert them to numbers.

I decided that A Little Important was the baseline and basically represented a lack of opinion on the topic. These traits are the ones most people feel are nice to have but aren't requirements. Basically, a good programmer often has these traits but not having them doesn't mean you're not a good programmer. I recoded these values with 0 points.

Very Important and Completely Unimportant are the ratings that people used when they felt strongly about the item. That means that, respectively, the trait is either absolutely necessary to being a good programmer or the trait has no bearing on the quality of programmer you are whatsoever (or perhaps a little bit of a negative indicator). These values were recoded as 10 and -10 respectively.

The central values of Important and Negligible are what I call the non-committal values. You feel that they make a difference but they're not quite important enough to bank on them. I gave these a 3 and -3 respectively.

For example, "Has good problem solving skills" was rated Very Important and "Cheap" was rated Completely Unimportant. One could say, "someone with poor problem solving skills would make a poor programmer." On the other hand, you cannot say, "someone who is not cheap is a poor programmer." Of course, the contrapositive could also be stated that, "someone who is a good programmer is also a good problem solver." The contrapositive "someone who is a good programmer is also cheap" is considered by the community to be a largely invalid assertion.

"Fast" and "Co-located" appear nearest to the baseline. This may be due to the fact that many of the respondents didn't know what I meant by co-located. In any case, one might say, "a good programmer is a good programmer whether or not she's in the same building," or that "just because you're fast doesn't mean you're good and just because you're slow doesn't mean you're bad."

"Communicates effectively" and "Interested in helping teammates" are moderately rated in favor of contributing to being a good programmer while the two "college degree" items are rated moderately against contributing to being a good programmer. For example, you might know a lot of programmers who are great developers but who lack the social skills or interest to become good communicators or team players. As a result, you might say that good programmers often communicate effectively and help teammates, but some good programmers cannot.

You might also say, "Many people without college degrees, let alone a computer science degree, are great programmers. Thus, while having a degree is helpful, you can learn to be a great programmer without it."

Now, I feel it is worth noting that "unimportant" does not mean "negative." Just because most of the development community feels that having a CS degree or other certifications is unimportant to being a good programmer, it doesn't mean that the degree itself is unimportant. It just means that having the degree won't make you a good programmer; you still have a lot of learning to do.

With notes on the analysis out of the way, what do you say we take a look at some data? Currently, the new Google charts won't let me force the display of the categories, so you'll have to hover over the dots you're interested in. Here's a legacy chart you can look at if the javascript version below is unsatisfactory. The legacy chart has current data; it's just not as fancy as this one:
I'm sure you noticed there are two series in this graph. All Responses represents the average responses for all respondents; however, as you noticed in the respondent histogram that I have a dramatically unbalanced sample with programmers outnumbering all other groups combined by almost 3 to 1. To get a more accurate representation of the "general feel" of the community, I included the Group Average measure. This is the average of the averages. It's sort of the electoral college of informal research.

This chart demonstrates the average responses for each group:

Improving Search Performance when using SQL Server 2008 Encrypted Columns

ConfidentialThis is a story of courage, honor, and data encryption. In addition to being something of a tribute to one of my favorite games of all time, I do feel I need to preface this post with a bit of a disclaimer.

Generally, when I describe this problem to someone, we go through pretty much the same conversation.
Why didn't you try Sql Server 2008 Transparent Data Encryption? Why don't you just update your ACL? Why don't you try this? Or that?

Well, sometimes the environment, either technologically or politically, precludes some of your better options. Ultimately, you have to go with your best permissible solution to solve the problem at hand. That being said, let's say you've been charged with securing your organizations PII. Your only option is to encrypt the column with SQL Server's column encryption.

You start looking at the impact this is going to have on your current and future applications. If you're like me, one of the first concerns you're going to have is performance. For example, let's say you have the need to search on the encrypted field. A good example of an encrypted field that you'll likely have to search is the Social Security Number.

In my original benchmarks, I found the following results:Knowing that I was going to have to improve this performance, I started playing with some searching alternatives. First of all, it's obviously much faster to search an indexed column (especially one that is clustered), so my first goal was to generate an indexed column.

Ryan McGarty (my best friend and a damn fine programmer) and I discussed and quickly ruled out a basic hash. Sure, it'd be fast to search an indexed column containing the hash value, but that opens you up to a relatively simple plain text attack (especially with a known set of possible values). I decided that you could reduce the threat and still speed up the search by using hash buckets a la hashtables instead.

I concocted a hash function that produced a reasonable distribution within the buckets. My good friend and esteemed colleague David Govek pointed out that an MD5 hash would produce a pretty effective distribution between buckets (with high cardinality data like the social security number. David was right and I ended up with this hash function:
CREATE FUNCTION [dbo].[GroupData] 
(
 @String VARCHAR(MAX),
 @Divisor INT
) 
RETURNS INT
AS BEGIN

  DECLARE @Result INT;
  
  SET @Result = HASHBYTES('MD5', @String);
  
  IF (@Divisor > 0)
    SET @Result =  @Result % @Divisor;
  
  RETURN @Result;

END
I created the test data just as I had before, except that this time I also added the hash bucket. I created a clustered index on the bucket and I changed my select statement a little:
-- original select statement
SELECT *
FROM PersonData
WHERE 
  CONVERT(CHAR(9), DECRYPTBYKEY(SocialSecurityNumberEncrypted)) = '457555462'

-- hash key select statement
-- @Divisor is the divisor for the modulus operation in the hash function
SELECT *
FROM PersonData
WHERE 
  SocialSecurityNumberGroup = dbo.GroupData('457555462', @Divisor) AND
  CONVERT(CHAR(9), DECRYPTBYKEY(SocialSecurityNumberEncrypted)) = '457555462'

Here are my results:

So, what of the known plain text attack then?

So, I don't want to gloss over the plain text attack issue. Given the possible set of socials, the hashes would be very unlikely to have a collision. Thus, for most people, you'd be able to get their socials easily by hashing every possible social and joining to that table. By modulo dividing the hash value, I'm able to evenly distribute social security numbers among a known set of buckets. That means, I can control the approximate number of socials in each bucket given my set of values. I generally aim for about 1000 socials per bucket.

For example, an MD5 % 100 has a possible set of values from -100 to +100. That's 201 buckets so if you have 2010 rows of data to hash, you'll have about 10 rows per bucket. The benefit is that you now only have to decrypt 10 rows to find the exact row you're looking for. The detriment is that you've narrowed your possible result set. Within your own data set, you'd have narrowed it to 10 possible plaintext values; however, given that these values are unknown, you then have to look at the set of possible values.

Social security numbers have a set of possible values less than 1,000,000,000. It's hard to say exactly how many of them are the possible set of values, so let's say we're using only those socials currently in use by living Americans. The population of the United States at the time of writing was about 312,000,000. As I said, I usually aim for about 1,000 records per bucket. If I have 1,000,000 rows of data, I would modulo divide by 500 (1,001 buckets). If you knew my set of values, then you'd only have 1,000 possible values to reduce. Given that you know when and where I was born, you could probably narrow it to 20 or so possible socials.

But, you don't know my set of values, so you really have 312,000 values to chose from. Even if you did know the first 5 digits of my social security number (based on my state of issuance and my date of birth), your set of possible options would be so large, you'd probably be better off just pulling my credit report and getting my social that way.

Thus, while it seems to introduce a weakness to plain text attacks (and with low cardinality data it would be an issue), in the case of social security numbers, I don't believe it to be a reasonable attack.