30 May

How I got started as a developer

A response to a request for everyone to share how they got started down the road to become software developer.

I wrote my first code on a Kaypro II.  My mother bought it around 1987, and there were 2 things you could do on it.  You could use the word processor (I think it was WordStar) or you could program in some variant of BASIC.  I did a little of both.

My mother had a handful of programming books left over from getting her Associates degree a few years earlier, and I would copy some of the sample applications, or try to do some of the problems in some of the chapters.  Between the things the books left out and the bugs I added while hunting and pecking the code into the computer I had plenty of debugging to do.  In some ways I wish I had some of that code, but mostly I’m glad the evidence has been destroyed.

Next my mother bought an IBM pc running Windows.  My recollection was 3.1, but I’m almost certain I got it before 1992 so who knows?  I don’t remember how much ram it had, maybe a couple of MB?  I do remember the disk was 25mb.

The first challenge with that was to try to get this one flight simulator running on it.  I spent weeks modifying the autoexec.bat and config.sys on a boot disk to loaded the absolute bare minimum into memory and get every configured just right to be able that flight sim.  Then I spent countless hours playing purchased and/or pirated games and playing in Q-Basic.

Around that same time I got a programmable calculator for my high school math class.  I started writing programs to do the math problems for me.  I still had to show the work, but I could be certain the answer was correct.  I also created a simple black jack game and a two player howitzer game with random landscape and wind.

All that and I chose sports medicine as my major in college?  Yup.  How I got from sport medicine back to software development would be a whole post in itself.

So really, it was my Mom who got me started down this path.  She not only bought the computers, but she taught me how to debug.  How to work through the problems.  How to go step by step until you see where things where things go wrong.  Skills I still use every day.

Thanks Mom.

What’s your story?

24 May

T4 Generated Wrapper for a WCF Client

Background

The idea for this article came from two places:

I’m writing an application that gets all of its data from a WCF service. Each time I call the WCF service, I end up having to write a bunch of duplicate code and of course I don’t like to type, so I was trying to find a way to not have to write that code.
The app I’m developing is an internal business application, and we release weekly. Each release to the WCF services could be incompatible with the previous client. That means that I need to do the release during off hours. I don’t like working nights, so I wanted to find a way to have multiple copies of the service running and have the client choose which service to access based on its version, but I didn’t want to have to keep changing the config file for the client with each release.
First I’ll solve those two problems, and then I’ll demonstrate how to use T4 to generate this wrapper from the WCF service reference.

Prerequisites

To run the code, you’ll need to download and install the T4Toolbox.

Problem #1

A typical WCF call looks like this:

var proxy = new WCFServiceWrapper.WcfSvc.Service1Client()
try
{
    returnValue = proxy.GetData(value);
    proxy.Close();
}
catch
{
    proxy.Abort();
    throw;
}
Proxy = null;

To keep from having to write all that code every time I make a call to the WCF service, I created a static class that has a static method with the same signature as the WCF method I’m calling.

public static partial class SvcWrapper
{   
    public static string GetData(int value)
    {
        var proxy = GetServiceClient()
        try
        {
            var returnValue = proxy.GetData(value);
            proxy.Close();
            return returnValue;
        }
        catch
        {
            proxy.Abort();
            throw;
        }
    }
}

Now that same call that took 12 lines of code is now just this one line:

returnValue = SvcWrapper.GetData(value); 

Problem #2

To solve the second problem, I just added another method that creates an instance of the service client for me.

public partial class SvcWrapper
{
    private static string _serviceAddress;
    private static string _configName;
    private static bool _needsConfig = true;
    internal static WcfSvc.Service1Client GetServiceClient()
    {
        if (_needsConfig)
        {
            //At this point I'd do some hoopajoop to determine what the
            //current service address is for this version
            //something like:
  
            //ServiceConfig config = SomeWCFService.GetServiceConfig(versionNo);
            //_serviceAddress = config.Address;
            //_configName = config.ClientEndPointName;
            //The address of the service endpoint
            _serviceAddress = "http://localhost:50324/Service1.svc"

            //This string is the Name of the Client Endpoint
            //as defined in the running EXE's app.config
            _configName = "WSHttpBinding_IService1";
        }
        return new WCFServiceWrapper.WcfSvc.Service1Client(_configName, _serviceAddress);
    }
}

There’s nothing earth shattering about that code, and I haven’t even implemented the look of the address and config yet, but the shell is there for me to finish at a later date. But now if I want to add another endpoint configuration to the app.config file for this service, I can do that and have only one place to change which endpoint the app uses.

Using T4 to Generate Wrapper Methods

Now, I’ve solved my original 2 problems, but I’ve created another one. I’m going to have to create and maintain a wrapper method for every method exposed by the WCF Service. This is the perfect opportunity to do a little code generation with T4.

First thing you need to do is add references to the EnvDTE and T4ToolBox. Then add a new text file called GenerateServiceWrapper.t4. This file holds the code that is not specific to the service we’re wrapping, and the t4 extension doesn’t create the child .cs file that the .tt extension creates.

This file has 5 methods:

GetServiceInterface – takes the name of the service and searches the project for a file that matches. Then it calls FindInterface.
FindInterface – takes a project item and searches it for an interface. It returns the first one it finds, and nullif it doesn’t find one. It could maybe use some error handling but…
GetMethodSignature – this takes one of the public methods found on the interface and returns a string that will be the method signature of the wrapper method.
GetMethodCall – this takes one of the public methods found on the interface and returns a string that will be the call to that method on the WCF Service.
GetServiceWrapper – is where the rubber meets the road. This calls GetServiceInterface to get the interface, loops through the public methods and generates the wrapper methods.
Here’s the contents of that file, you’ll need to get a third-party plugin to get syntax highlighting in Visual Studio.

<#@ Template Language="C#" #>
<#@ import namespace="EnvDTE" #>
<#@ include File="T4Toolbox.tt" #>
<#+
public void GetServiceWrapper(string LocalServiceName)
{
    EnvDTE.CodeInterface svcInterface =
    GetServiceInterface(LocalServiceName + @"\reference.cs");
    foreach (var ce in svcInterface.Members)
    {
        var meth = ce as CodeFunction;
        if (meth != null)
        {
            if (meth.Access == vsCMAccess.vsCMAccessPublic)
            {
                string methodSignature = GetMethodSignature(meth);
                string methodCall = GetMethodCall(meth);
                bool returnsVoid = false;
                if (meth.Type.AsString.Equals("void"))
                {
                    returnsVoid = true;
                }
                #>
        <#=methodSignature #>
        {
            var proxy = GetServiceClient();
            try
            {
            <#+
                if (returnsVoid)
                {
                       #>    proxy.<#=methodCall #>;
                            proxy.Close();
            <#+
                }
                else
                {
            #>    var returnValue = proxy.<#=methodCall #>;
                proxy.Close();
                return returnValue;
<#+
                }
#>
            }
            catch
            {
                proxy.Abort();
                throw;
            }
        }
         
<#+
            }
        }
    }
}
 
public EnvDTE.CodeInterface GetServiceInterface(string interfaceFile)
{
    ProjectItem projectItem = TransformationContext.FindProjectItem(interfaceFile);
    FileCodeModel codeModel = projectItem.FileCodeModel;
    return FindInterface(codeModel.CodeElements);
}
 
public CodeInterface FindInterface(CodeElements elements)
{
    foreach (CodeElement element in elements)
    {
        CodeInterface myInterface = element as CodeInterface;
        if (myInterface != null)
            return myInterface;
        myInterface = FindInterface(element.Children);
        if (myInterface != null)
            return myInterface;
    }
    return null;
}
 
public string GetMethodSignature(CodeFunction method)
{
    var methodSignature = new System.Text.StringBuilder();
    methodSignature.Append("public static ");
    methodSignature.Append(method.Type.AsString);
    methodSignature.Append(" ");
    methodSignature.Append(method.Name);
    methodSignature.Append("(");

    bool isFirstParameter = true;

    foreach (var prm in method.Parameters)
    {
        CodeParameter p = prm as CodeParameter;
        if (!isFirstParameter)
        {
            methodSignature.Append(", ");
        }
        else
        {
            isFirstParameter = false;
        }

        methodSignature.Append(p.Type.AsString);
        methodSignature.Append(" ");
        methodSignature.Append(p.Name);
    }

    methodSignature.Append(")");

    return methodSignature.ToString();
}
 
public string GetMethodCall(CodeFunction method)
{
    var methodCall = new System.Text.StringBuilder();
    methodCall.Append(method.Name);
    methodCall.Append("(");

    bool isFirstParameter = true;

    foreach (var prm in method.Parameters)
    {
        CodeParameter p = prm as CodeParameter;

        if (!isFirstParameter)
        {
            methodCall.Append(", ");
        }
        else
        {
            isFirstParameter = false;
        }
        methodCall.Append(p.Name);
    }
    methodCall.Append(")");
    return methodCall.ToString();
}      
#>

Lastly create a text file named ServiceWrapper.tt, or something less generic as this will define the actual wrapper for the WCF Service.

It contains a link to our GenerateServiceWrapper.t4 file, the definition of our class, and a call to GetServiceWrapper to which we pass the name of the WCF Service Reference.

<#@ template language="C#v3.5" hostspecific="True" #>
<#@ include File="T4Templates\GenerateServiceWrapper.t4" #>
using System;
 
namespace WCFServiceWrapper
{
    public static partial class SvcWrapper
    {   
<#      GetServiceWrapper("WcfSvc");#>
    }
}

Once you save, it should generate a SvcWrapper.cs file with static methods to wrap all of your calls. Now if I want to do something like add logging to each WCF call, all I have to do is add that code to the GetServiceWrapper method in the GenerateService.t4 file, poof all my methods WCF calls are logged.

Notice that I created this class as a partial class, this allows us to put the GetServiceClient method in the same class, but in a separate file. We could have either created that method in a completely separate class, or within the ServiceWrapper.tt file. You never want to edit the generated file, as those edits will be overwritten.

Points of Interest

Syntax highlight for T4 requires a 3rd party plugin. I’ve tried a few, and they are all pretty weak.

You can’t step through T4 code (or I haven’t figured out how), so it can take some serious guess and check to figure out what’s going wrong when something goes wrong. The output window is your friend.

22 May

App Reviews

A quick word about app reviews:

  • Most people don’t review.  I average about 1000 ad impressions a day.  In other words users are playing 1000 minutes a day.  So there are people who are using Chess Tactics but are not reviewing it.  There have been about 1500 downloads, and only 8 reviews in the US.
  • Most reviews are not that helpful.  I have a handful of reviews that are on the low-end with no indication about what they don’t like.  Either they left it blank or just state they didn’t like it.  One Australian rated it a 1 star and commented that he wished he could give it zero stars.
  • Fixing complaints doesn’t necessarily raise your rating.  There were a couple of reviews that complained about having time factored into the scoring.  I put out an update that allowed them the option to remove the time factor from the scoring.  One reviewer did re-rate the app, but they left the negative part of the review, and just added that it was fixed at the end.  The other reviewer hasn’t changed his rating yet.
  • It’s hard not to take it personally.  I worked hard on the app in my and the negative feedback is frustrating.  I just have to keep in mind that even wildly successful products have a handful of people who think it’s crap.  Just take a look at the review for any product on Amazon.

What I really wish was available through the review system was a way to reach out to those who did review the app, or respond to reviews.  How nice would it be to attach a comment to a low review that disliked the time factor is scoring to let them and the world know that I took their feedback and fixed their issue.  Or maybe it would be nice to email the user, but I understand that could open up an opportunity for abusing negative voters.

I did include a feedback email address in my app, and I have received responses from 2 users.  One had a question about a particular problem, and the other suggested an option to keep the phone from sleeping (coming next release).  I really enjoyed those interactions, and I hope there are more.

Finally, I hope this experience changes the way I review apps and give feedback.  If it’s at all possible I will give specific feedback in the review.  I’ll also try to follow-up with an email so they can let me know if they change what I didn’t like about an app, so that I can adjust my review.

20 May

Minimum Requirements

The Visual Studio team just announced that the Visual Studio 11 will have the same hardware requirements as Visual Studio 2010.  So, we’re getting more features, they’ve improved the performance throughout (yes, I am using it and the differences are obvious in places), and we could run it on yesterdays hardware, but we’re likely to have upgraded since then so faster still.

This seems to be a trend at Microsoft, or at least I hope it is.  Earlier this year (or was it at Build last September) they announced that they had improved the performance and memory usage in Window 8 to the point where it was faster than Windows 7, used less memory and that the minimum requirements wouldn’t change from the Windows 7 minimums.

For so many years improvements in hardware were negated by bloat in software.  If this trend continues we should be computing noticeably faster in a few years.  Combine that with Microsoft’s push around asynchronous programming and the user experience a few years from now could be vastly better than it is today.

Of course Microsoft can only do so much, it’s now up to the world 3rd party and in-house developers to take up the challenge and write software that uses less memory, performs better and runs all long running processes asynchronously.  Microsoft targeted processes that take longer than 50 ms, I might raise my target a bit above that, but I am accepting the challenge.

12 May

Mobile Analytics

In my previous post I complained about the 6 day delay in getting download number from Microsoft.  Since then I have done a little bit of research into other ways of getting that information in a more timely manner.  I found two good options MTIKS and Flurry.  They both provide much more information than I was looking for from Microsoft, and I will be using one or the other unless I find something better.

They are both very easy to use.  All you need to do is add a reference to their dll, then add one line of code to Application_Launching and Application_Activated to tell them to start a session, and another line to Application_Deactivated and Application_Closing to tell them to end the session.

They both also allow you to report exceptions and events.  This would allow me to see how many problems users are playing, or what percentage of users turn off time based scoring in Chess Tactics.

Of course each has their strength and weakness.

MTIKS

MTIKS biggest strength is that it can detect pirated apps so you can see how big of a problem pirated apps are for you.  My apps are all free at this point, so I’m not worried about pirates, and this feature isn’t a great selling point for me.

The other thing I really like about MTIKS was that it was real time (or very close to it).  I could start up a session in the emulator, click refresh on their site and see the session.

The one problem I did see with MTIKS is in their exception handling.  The stack trace gets overwritten if you log the error for Application_UnhandledException.  I contacted them about this and they responded quickly and are looking into the problem.  I’ll update this when they fix it.

Flurry

Flurry looks like it does a great job on the reporting side.  They allow you to compare your app to the aggregate data of other apps collecting the same info.  It lets you segment your reporting based on your users age, gender, language, location and even custom events (user who clicked the review this app button for example).  If you’re not collecting this information, Flurry will make some estimates for you.

The downside here is that Flurry runs on a about a 1 hour delay.  I of course would prefer instant gratification, but 1 hour isn’t too long to wait.  Right now I’m facing a 6 day delay in download numbers and a 3 day delay in exception reporting, so one hour seems totally resonable.

10 May

Microsoft’s App Reporting

Warning, this is going to be a bit of a rant, but it’s been driving me crazy for a little while.

If you’re following along (and chances are no one is) you know that I recently released my first app for Windows Phone.  Since then, I have been following the apps progress in downloads and ad revenue through Microsoft’s provided reporting tools on both PubCenter and AppHub.  The reports are pretty decent for the most part, and give me the data I’m looking for except for 1 things.  The lag in data.

The data for ad revenue is delayed by 3-6 hours (I’ve seen as much as 12 hours).  It drove me crazy when I first released the app because it was the only data I could get.   I’ve made my peace with this and I now only check the previous day’s total, and I don’t do that every day.

The delay that really grinds my gears is the downloads number in the AppHub.  That number is delayed 6 days.  There reasoning?  That’s how long it takes to process credit card transactions.

Wait, I wasn’t reporting on number of sales, I was reporting on number of downloads.  People can download my app for free, other apps have a trial period.  Why are the download numbers for those being delayed?  If your app is trial/buy, the report doesn’t give you an accurate reflection of sales, nor does it give you an up to date number of downloads.

I suggest this:  Allow us to view reports of downloads and trials in a much more up to date fashion.  A 1 day delay at most.  And have another option to view the number of sales which would be delayed by the 6 days it takes to process a credit card.