Friday, December 14, 2007

A consistently applied naming convention in code is a corner stone in structured programming. But they are not sacred.

When I do code reviews, I spend time analyzing naming conventions:

  • Are there any conventions present?
  • Are the conventions consistently applied?

In my own code, I am no different. Naming conventions help programmers share code, ease debugging and enhances code readability.

In my journey from Visual Basic to .NET and C#, I have touched a couple of common conventions. In the current project in which I am pushing a legacy eVB-project to .NETCF and C#, I have come to an insight.

My first ambition was to replace the eVB-esque naming convention with .NET and C#-flavored one. I spent a lot of time renaming objects, classes and visual elements. Too much time. I felt that about half of my time was wasted doing nothing valuable. I decided to revert back to old eVB naming conventions and now the entire experience is much more efficient. I can move large chunks of code and just do minor changes instead of having to rewrite everything.

Once I am done and have a mirror application in .NETCF, then I can revisit the naming conventions used more efficiently using refactoring-utilities. Until then, it's full speed ahead.

posted on Friday, December 14, 2007 2:52:52 PM UTC  by Andy  #    Comments [0]
 Friday, December 07, 2007

For weeks I've been avoiding it, but today (during lunch) I had to do the pre-insurance inspection of my car. The reason for pushing it back should be obvious for anyone that have gone through the procedure. Even if I'm used to catching up on my blog readings while waiting, it's a testing experience. My hopes didn't exactly go up when I arrived and was ordered back to the far end of the long line.

photoinspectionBut, this time I was greatly surprised! Even if I had time for a few blogs, the wait was not close to what I had expected (about 30 minutes with five cars before mine). The inspector hardly looked at me (yes, he was an efficient guy), took the papers of my car, and got instantly busy. I was amazed how fast he worked, and when I saw that he was constantly tapping in everything that he saw and heard (from both the car and me), I asked what he was using. He showed me the device (a Qtek 9100 a k a HTC Wizard), and when I said "Ok, you got Windows in that" he instantly replied "Yes, it works great!". You can see the only photo I got (as I said, he was a busy man) on the right, and I'm sorry for the bad quality. But I can tell you that the application was very well designed and I was surprised that the UX had so much information (really small fonts were used to fit in as much info as possible). All the necessary photos of the car was captured with the built-in camera and there was no hassle what so ever for the inspector (he took the picture, tapped a few times, and took the next, and so on). He said that an inspection that took more than double the time before, created even more work afterwards (data entry, photo transfer, etc).

Apart from the great UX, I was really impressed by another thing - EVERYTHING ended up digitalized. The parts of the process that was governed by law (or the insurance company) to be on paper was rapidly filled in (hardly readable) and then he took a photo of the paper, and threw it in a large green bin with a yellow label saying "to archive" (it actually looked like a large recycle bin, which it probably what it should have been if the correct laws and directions were in place). After I had signed the final paper, he took a photo of it, threw it in the bin, shook my hand, and turned to the next in line. I was AMAZED! The inspector expected that from the point where the insurance company assigned them an inspection to the point where the completed inspection was approved by the insurance company was reduced by 80%. Still, he said that the largest benefit for him was that many irritating and stressing events (the person responsible for data entry coming back with questions, the need to start another inspection before one was completed due to wait for some manual step, etc) was gone.

To my point, and the title of this post. I have been involved in WM development for eight years, and I have seen many systems come alive. All have led to increased productivity and efficiency, and all have led to large cost cuts or even revenue and profit increase. But I haven't seen many examples of where the legacy process was completely replaced by a digitalized and mobile process. Often many manual steps remain for various reasons (mostly legal or related to company policy), and often it is those steps that reduce the possible gains drastically. The post title is a reference to a British movie about going all the way, and my lesson again today, and hopefully yours too: We need to go all the way in making processes (mostly papers) digital (yes, everything that Bill Gates wrote is true), and that is many times more important when designing mobile solutions. The inspector I met today was doing his work in the "current moment" or "now" by performing what I call "JitBiz" ("Just-in-time Business", referencing both managed compilers as well as the old idea by Henry Ford not to keep any stock), and by doing that he was also relived of "worry" (for things that was waiting for him) and "regret" (for things that needed follow-up). This is the way all companies should work for the sacred trinity; the customer, the business, and the (holy) employee.

posted on Friday, December 07, 2007 8:31:16 PM UTC  by Chris  #    Comments [0]
 Tuesday, December 04, 2007

As a follow-up on my post I Want More Mobile (Web) Services, I will continue with something very common that I want to do with my WM device - look up flight status info. One of the best public services for that is FlightExplorer, and therefore I decided to scrape their site to get the info that I want. Just as I suggested in the previous post, I have now created a ASP.NET Web Service application that takes care of the actual scraping, and the mobile client simply capture the parameter, calls the web service, and present the result. A minimum of information is transferred over the wire, and therefore this solution is very fast and cost effective.

If you want to get right to the code, I have created my second CodePlex project called Windows Mobile Web Services. If you want to be part of the development, please let me know.

Starting with the front end, flightscrapeyou can see the UX on the right, and the client code looks like this...

WebServices.Service ws = new WebServices.Service();
resultTextBox.Text = ws.FlightLookup(flightTextBox.Text).Replace("\n", "\r\n");

...and on the server side, the code begins like this...

[WebMethod]
public string FlightLookup(string flight)
{
   
// Get session cookie and viewstate
    CookieContainer cookies = new CookieContainer();
    string url = "http://travel.flightexplorer.com/TrackFlight.aspx";
   
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
    request.UserAgent = USER_AGENT;
    request.CookieContainer = cookies;
   
StreamReader responseReader = new StreamReader(request.GetResponse().GetResponseStream());
   
string responseData = responseReader.ReadToEnd();
    responseReader.Close();

   
// Extract the viewstate value and build POST data
    string viewState = extractValue(responseData, "__VIEWSTATE");
   
string postData = String.Format("__VIEWSTATE={0}&leftcol1...flightNum={1}&FastTrack1...",
        viewState, flight);

   
// Now post to the same page
    request = WebRequest.Create(url) as HttpWebRequest;
    request.UserAgent = USER_AGENT;
    request.Method =
"POST";
    request.ContentType =
"application/x-www-form-urlencoded";
    request.CookieContainer = cookies;
   
StreamWriter requestWriter = new StreamWriter(request.GetRequestStream());
    requestWriter.Write(postData);
    requestWriter.Close();
    responseReader =
new StreamReader(request.GetResponse().GetResponseStream());
    responseData = responseReader.ReadToEnd();
    responseReader.Close();

...and this is a typical approach when scraping ASP.NET web applications (note, the above code is simplified to increase readability). First the page is requested without any parameters, just to get the session state cookie and the view state, and then a POST is made to the same page with the cookie and the form data created using the view state. When the resulting page content is captured, it's parsed like this...

    // Get flight status
    int i = 0;
   
string status = null;
   
string result = "Flight not found";
   
if(responseData.IndexOf(result) < 0)
    {
       
string s = "Status:";
       
if((i = responseData.IndexOf(">" + s + "<")) > -1)
        {
            i = responseData.IndexOf(
"class='ft1'>", i) + 12;
            status = responseData.Substring(i, responseData.IndexOf(
"<", i) - i);
            result =
string.Format("{0} {1}", s, status);
           
switch(status)
            {
               
case "Planned":
                    s =
"Departure in:";
                    i = responseData.IndexOf(
">" + s + "<", i);
                    i = responseData.IndexOf(
"FTText2' colspan=3>", i) + 19;
                    result +=
string.Format("\n{0} {1}", s,
                       
responseData.Substring(i, responseData.IndexOf("<", i) - i));
                   
break;
               
case "In Flight":
                    s =
"Time remaining:";
                    i = responseData.IndexOf(
">" + s + "<", i);
                    i = responseData.IndexOf(
"class='ft1'>", i) + 12;
                    result +=
string.Format("\n{0} {1}", s,
                       
responseData.Substring(i, responseData.IndexOf("<", i) - i));
                   
break;
            }
        }
    }
   
return result;
}

...and here is the helper method for extracting form values (it's very generic, and can be used in most ASP.NET scraping)...

private string extractValue(string s, string nameDelimiter)
{
   
string valueDelimiter = "value=\"";

   
int namePosition = s.IndexOf(nameDelimiter);
   
int valuePosition = s.IndexOf(valueDelimiter, namePosition);
   
if(namePosition < 0 || valuePosition < 0)
       
return string.Empty;
   
int startPosition = valuePosition + valueDelimiter.Length;
   
int endPosition = s.IndexOf("\"", startPosition);

   
return HttpUtility.UrlEncode(s.Substring(startPosition, endPosition - startPosition));
}

Finally, I also want to mention a detail in the client implementation. To ease entering the flight id, the input mode changes depending on number of characters entered. For the first three, the input mode is alphanumeric, and otherwise it's numeric. The code looks like this...

private bool inputNumeric = false;
private void flightTextBox_TextChanged(object sender, EventArgs e)
{
   
if(flightTextBox.Text.Length >= 3 && !inputNumeric)
    {
       
InputModeEditor.SetInputMode(flightTextBox, InputMode.Numeric);
        inputNumeric =
true;
    }
   
else if(flightTextBox.Text.Length < 3 && inputNumeric)
    {
       
InputModeEditor.SetInputMode(flightTextBox, InputMode.Default);
        inputNumeric =
false;
    }
}

...and the use of the private variable is just to prevent unnecessary input mode changes (the InputModeEditor class is in the Microsoft.WindowsCE.Forms namespace).

I will continue my quest for more, simple, but very usable Web Services, and any suggestions are most welcome. Just point me to a site and how it could be made available in an efficient way from a WM device...

posted on Tuesday, December 04, 2007 9:20:37 PM UTC  by Chris  #    Comments [0]
 Sunday, December 02, 2007

So, my first CodePlex project is in the air, and it's called Web Service Compression for Compact Framework. I have made the first public released available today, and if you want to take part in further development, just let me know and I'll add you to the project.

This project started with an article called Web Service Compression with .NET CF that focused on standard HTTP 1.1 Compression, and in that article you can find some interesting results from using compression. The main lessons learned was "On small payloads the saving is at least 50%, and on larger payloads, more than 90% compression, and cost saving, can be achieved. When it comes to performance, the tests show that for small payloads, we have to pay a performance penalty of about 20%, but for larger payloads, we actually get a performance win of about 50%". The idea was developed further in the article Two-Way .NET CF Web Service Compression when the idea of also compressing the requests from the WM device was introduced. The approach used SOAP Extensions, and that is still true for the code in the new CodePlex project.

The fact that compression is now included in CF means that I had to say goodbye to an old and dear friend - SharpZipLib (many thanks, Mike Krüger and the rest of the team). I have used this library in numerous projects through the years, and it has served me very well. The best thing with saying bye was, when converting to the System.IO.Compression namespace, that only two lines of code needed change.

I think that a future direction for this project could be to support WCF services, and as there are several ways to approach that, I was thinking about behaviors...

posted on Sunday, December 02, 2007 4:00:52 AM UTC  by Chris  #    Comments [0]