Fear and Loathing

Gonzo blogging from the Annie Leibovitz of the software development world.

  • SharePoint Content and Site Editing Tips

    A few content management and site editing tips for power users on this bacon flavoured unicorn morning. The theme here is keep it clean!

    • Write "friendly" email addresses
      • Remember it's human beings reading your content. So seeing something like "If you have questions please send an email to Corporate.Comm@mycompany.com" breaks up the readiblity. Instead just do the simple steps of writing the content in plain English and going back, highlighting the name and insert a link (note: you might have to prefix the link with mailto:first.last@yourcompany.com). It makes for a friendlier looking page and hides the ugliness that are sometimes in email addresses.
    • Use friendly column and list names
      • This is a big pet peeve of mine. When you first create a column or list with spaces the internal name is changed. The display name might be "My Amazing List of Animals with Large Testicles" but the internal (and link) name becomes "My_x00x20_Amazing_x00x20_List_x00x20_of_x00x20_Animals_x00x20_with_x00x20_Large_x00x20_Testicles". What's worse is if you create a publishing page named "This Website is Fueled By a Dolphin's Spleen". Not only is it incorrect grammar, but the apostrophe wreaks havoc on both the internal name for the list (with lots of crazy hex codes) as well as the hyperlink (where everything is uuencoded). Instead create the list with a distinct and compact name then go back and change it to whatever you want. The end result is a better formed name that you can both script and access in code easier.
    • Keep your Views Clean
      • When you add a column to a list or create a new list the default is to add it to the default view. Do everyone a favour and don't check this box! The default view of a list should be something similar to the Title field and nothing else. Keep it clean. If you want to set a defalt view that's different, go back and create one with all the fields and filtering and sorting columns you want and set it as default. It's a good idea to keep the original AllItems.aspx (note the lack of space in the filename!) easy and unfiltered. It's also a good idea to keep your column count down in views. Don't let every column be added by default and don't add every column just because you can. Create separate views for distinct responsibilities and try to keep the number of columns down to a single screen to prevent horizontal scrolling.
    • Simple Navigation
      • The Quick Launch is a great tool for navigating around your site but don't use the default of adding all lists to it. Uncheck that box and keep navigation simple. Create custom groupings that make sense so if you don't have a site with "Documents and Lists" but "Reports and Notices" makes more sense then do it. Also hide internal lists from the Quick Launch. For example, if most users don't need to see all the lookup tables you might have on a site don't show them. You can use audience filtering on the Quick Launch if you want to hide admin items from non-admin users so consider that as an option.

    Enjoy!

  • WP7 Mobile Friendly WordPress Site

    If you're running a WordPress site you owe it to yourself to check out WPTouch. WPTouch is a fabulous plug-in for WordPress that instantly transforms your site into a navigatable mobile friendly one.

    Browse to a WordPress site and it's pretty clean. Here's my site using the default Twenty Ten theme in my Windows Phone 7 IE browser:

    Without WPTouch

    That's pretty good. In fact, comparing it to the site in the browser it's identical. However navigating tiny links on the site or menus can be tedius with fat fingers. Sure, mobile devices offer pinch zoom and features like that but do you really want to be constantly zooming in, panning around, and zooming back out to read content?

    Andrew Woodward over at 21apps turned me onto a WordPress plugin called WPTouch this weekend so I thought I would give it a go. I have a few sites I run on WordPress and I wanted to see what it could do. Wow. What a transformation. Once you install and activate the WPTouch plugin (all from the comfort of your WordPress dashboard) your site will magically be transformed into this:

    With WPTouch Enabled

    My WordPress site looks like an iPhone app! No software to install on the client, this is all magically done behind the scenes by detecting the browser and serving up an alternate theme via the plug-in.

    To get it working for WP7 I had to add a quick modification to the settings. Once you're installed WPTouch and activated it (just add it through the built-in search in the WordPress dashboard, it's the first one to come up) then go to Settings > WPTouch. Scroll down to Advanced Options. There you'll see a list of currently enabled user-agents so the list is pretty full; Android, BlackBerry, iPhone, etc.

    What's missing is the user agent to detect the Windows Phone 7.

    Just add "iemobile" which is the lowest common denominator to the Custom user-agents box and save the settings. Visit your site with your WP7 phone and voila, everything will be right as rain.

    Don't worry about navigation as it's covered by a clever menu that's created by the plugin so you'll have access to tags, categories and any part of the site:

    Navigation with WPTouch

    The rest of the site looks awesome and your browser users will still continue to see the site with whatever theme you have applied. It's not perfect on WP7 as the theme is designed for iPhones but IMHO it's a far better experience than trying to tap on tiny links in a browser. Everything is big and bold, the way it should be on a mobile device.

    Finally, if you do decide to add the plugin (it's free, although there is a Pro version too) then show your WPTouch pride to your desktop browser users with a decal. The guys ask you link back to the site if you do. You grab whatever size and format image you want from here.

    WPTouch Pride!

    Hope that helps and here's to a better mobile experience from your WordPress site!

    P.S. The "boys" and I were discussing something like this for SharePoint. Yeah, it would be totally awesome if we had something like this which would serve up say a Metro view for WP7 phones. Not sure if it'll become a reality but food for thought.

  • Secret Agent Man

    Just a quick one this morning as we all get started in the week. Something that comes into play (sometimes in a big way) is the user agent string your browser gives off. So for example using the User-Agent field in the request header, you can determine what browser the user is running and act accordingly.

    Internet Explorer 9 modified the UA string slightly so just in case you're looking for it here are the user agent strings for IE9 (in various modes):

    • Internet Explorer 9 Mode: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
    • Internet Explorer 8 Mode: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; MS-RTC LM 8; InfoPath.3; .NET4.0C; .NET4.0E; Zune 4.7)
    • Internet Explorer 7 Mode: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; MS-RTC LM 8; InfoPath.3; .NET4.0C; .NET4.0E; Zune 4.7)
    • Internet Explorer 9 (Compatibility Mode): Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; MS-RTC LM 8; InfoPath.3; .NET4.0C; .NET4.0E; Zune 4.7)

    A couple of things to note here:

    • This was from a 64-bit Windows 7 client so that might account for the WOW64 in the agent string (I don't have a 32-bit client to test from)
    • Various applications and platforms add to the UA string just like they do in previous IE releases. So for example you can see I have various .NET versions installed as well as Zune. You can take advantage of this by querying the UA string for compatibilities and present options accordingly to the end user.
    • As applications will continue to add and modify this string you'll want to query the string for parts not the entire string. For example if you want to detect if you're coming from IE running  on a Windows Phone 7 just look for "iemobile" in the user agent string

    Happy hacking!

  • SharePoint Content Type Cheat Sheet

    Principle

    Any application or solution built in SharePoint must use a custom content type over adding columns to lists. The only exception to this is one-off solutions that have no life-cycle, proof-of-concepts, etc.

    Creating Content Types

    • Web UI. Not portable, POC only
    • C# or Declarative (XML). Must deploy these as Features

    Rule

    Do not chagne the base XML for a Content Type after deploying. The only exception to this rule is that you can re-deploy a modified Content Type definition only after completely removing it from the environment (either programatically or by hand).

    Updating Content Types

    • Update and push down to child types
      • Web UI. Manual for each environment. Document steps required for repeatability.
      • Feature Upgrade. Preferred solution.
      • C#. If you created the content type through code you might want to go this route.
    •  Create new modified Content Types and hide the old one. Not recommended but useful for legacy.

    References

    Agree or disagree?

  • Pet Peeves with the Windows Phone 7 Marketplace

    Have you ever noticed how something things just gnaw at your very being. This is the case with the WP7 marketplace, the Zune software, and the things that drive me batshit crazy with a side of fries. To go. I wanted to share.

    palinshrug

    XBox Live is Not the Centre of the Universe

    Okay, it’s fine that the Zune software has an XBox live tag for games so can see them clearly but do we really need to have it shoved down our throats. On every click?

    Click on Games in the marketplace:

    image

    The first thing that it defaults to on the filters on the right is XBox Live:

    image

    Okay. Fine. However if you change it (say to Paid) then click onto a title when you come back from that title is the filter still set to Paid? No. It’s back to XBox Live again.

    Really? Give us a break. If you change to any filter on any other genre then click on the selected title, it doesn’t revert back to anything. It stays on the selection you picked. Let’s be fair here. The Games genre should behave just like every other one. If I pick Paid then when I come back to the list please remember that.

    Double Dipping

    On the subject of XBox Live titles, Microsoft (and developers who have an agreement with Microsoft to produce Live titles, which generally rules out indie game developers) is double dipping with regards to exposure of their titles.

    Here’s the Puzzle and Trivia Game section on the Marketplace for XBox Live titles:

    image

    And here’s the same category filtered on Paid titles:

    image

    See the problem? Two indie titles while the rest are XBox Live ones. So while XBL has it’s filter, they also get to showcase their wares in the Paid and Free filters as well.

    If you’re going to have an XBox Live filter then use it and stop pushing down indie titles until they’re off the screen (on some genres this is already the case). Free and Paid titles should be just that and not include XBox Live ones. If you’re really stoked that people can’t find the Free XBox Live titles vs. the paid ones, then create a Free XBox Live filter and a Paid XBox Live filter. I don’t think we would mind much.

    Whose Trial is it Anyways?

    You might notice apps in the marketplace with titles like “My Fart App Professional Lite” or “Silicon Lamb Spleen Builder Free”. When you submit and app to the marketplace it can either be free or paid. If it’s a paid app you also have the option to submit it with Trial capabilities. It’s up to you to decide what you offer in the trial version but trial versions can be purchased from within the app so after someone trys out your app (for free) and wants to unlock the Super Secret Obama Spy Ring Level, they can just go to the marketplace from your app (if you built that functionality in) and upgrade to the paid version.

    However it creates a rift of sorts when it comes to visibility. Some developers go the route of the paid app with a trial version, others decide to submit *two* apps instead of one. One app is the “Free” or “Lite” verions and the other is the paid version. Why go to the hassle of submitting two apps when you can just create a trial version in the same app? Again, visibility.

    There’s no way to tell Paid apps with Trial versions and ones without (it’s an option, you don’t have to provide trial versions, although I think it’s a good idea). However there is a way to see the Free apps from the Paid ones so some submit the two apps and have the Free version have links to buy the paid one (again through the Marketplace tasks in the API).

    What we as developers need for visibility is a new filter. Trial. That’s it. It would simply filter on Paid apps that have trial capabilities and surface up those apps just like the free ones. If Microsoft added this filter to the marketplace, it would eliminate the need for people to submit their “Free” and “Lite” versions and make it easier for the developer not to have to maintain two systems. I mean, is it really that hard? Can’t be any more difficult than the XBox Live Filter that’s already there.

    Location is Everything

    The last thing on my bucket list is about location. When I launch Zune I’m running in my native location setting, Canada. What’s great is that I navigate to the Travel Tools section where I have one of my apps and behold the splendour that I see:

    image

    There are my apps in the number 1 and number 4 slot for top selling in that category. I show it to my wife to make up for the sleepless nights writing this stuff and we dance around and celebrate.

    Then I change my location on my operation system to United States and re-launch Zune. WTF?

    image

    My flight app has slipped to the 10th spot (I’m only showing 4 across here out of the 7 in Zune) and my border check app that was #1 is now in the 32nd spot! End of celebration.

    Not only is relevance being looked at here, I value the comments people make on may apps as do most developers. I want to respond to them and show them that I’m listening. The next version of my border app will provide multiple camera angles. However when I’m running in my native Canada location, I only see two reviews. Changing over to United States I see fourteen! While there are tools out there to provide with you a unified view, I shouldn’t have to rely on them. My own Zune desktop software should allow me to see everything.

    I realize that some developers will submit an app and only target it for some locations and that’s their choice. However I shouldn’t have to jump through hoops to see what apps are ahead of mine, or see people comments and ratings.

    Another proposal. Either unify the marketplace (i.e. when I’m looking at it show me everything combined) or let me choose a filter. I think the first option might be difficult as you’re trying to average out top selling apps across all markets and have to deal with some apps that have been omitted from some markets. Although I think you could come up with a set of use cases that would handle that, maybe that’s too much work. At the very least, let us developers view the markets in a drop down or something from within the Zune desktop. Having to shut down Zune, change our location, and re-launch Zune to see other perspectives is just too onerous.

    A Call to Action

    These are just one mans opinion. Do you agree? Disagree? Feel hungry for a bacon sandwich? Let everyone know via the comments below. Perhaps someone from Microsoft will be reading and take some of these ideas under advisement. Maybe not, but at least let’s get the word out that we really want to see some change. Egypt can do it, why not WP7 developers!

  • Applying Quotas Across all My Sites

    Just a quick snippet this morning. If you need to apply a new quota template to all users My Sites here's a quick script to do it. Changing an existing quota is fine but if you're migrating users from another system or you just want to up everyone's storage a bit here's what you do.

    1. Create a new quota template. This is found in Central Admin under Application Management | Site Collections | Specify quota templates. There's already a default "Individual Quota" created you might want to create your own or have a special one for your users
    2. Open up the PowerShell Management Console and enter "Get-SPWebApplication". This will list all your web applications on the farm. 
    3. To apply it to all My Sites (each site is a site collection of its own) run this script below.

       1:  $webapps = Get-SPWebApplication;
       2:   
       3:  $webapp = $webapps[4];
       4:   
       5:  foreach ($site in $webapp.Sites) {
       6:      Set-SPSite -Identity $site.url -QuotaTemplate "Your Quota Template"
       7:  }

    The first line gets all the web applications on the server. In our case, the forth one is the mysite web app (yours will probably be a different number). Just run Get-SPWebApplication from the console to figure out which one to use. You could get fancy and pipe the name to find it but I'm too lazy for that.

    Then we loop through all the sites on the list using the $site.url property and pass it to the Set-SPSite cmdlet and specify the name of the our custom QuotaTemplate.

    Easy. Now all users are updated with the new quota template.

  • Imperative vs. LINQ Performance on WP7

    Jesse Liberty had a nice post presenting the concepts around imperative, LINQ and fluent programming to populate a listbox. Check out the post as it’s a great example of some foundational things every .NET programmer should know.

    I was more interested in what the IL code that would be generated from imperative vs. LINQ was like and what the performance numbers are and how they differ.

    The code at the instruction level is interesting but not surprising. The imperative example with it’s creating lists and loops weighs in at about 60 instructions.

       1:  .method private hidebysig instance void ImperativeMethod() cil managed
       2:  {
       3:      .maxstack 3
       4:      .locals init (
       5:          [0] class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> someData,
       6:          [1] class [mscorlib]System.Collections.Generic.List`1<int32> inLoop,
       7:          [2] int32 n,
       8:          [3] class [mscorlib]System.Collections.Generic.IEnumerator`1<int32> CS$5$0000,
       9:          [4] bool CS$4$0001)
      10:      L_0000: nop 
      11:      L_0001: ldc.i4.1 
      12:      L_0002: ldc.i4.s 50
      13:      L_0004: call class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> [System.Core]System.Linq.Enumerable::Range(int32, int32)
      14:      L_0009: stloc.0 
      15:      L_000a: newobj instance void [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
      16:      L_000f: stloc.1 
      17:      L_0010: nop 
      18:      L_0011: ldloc.0 
      19:      L_0012: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> [mscorlib]System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator()
      20:      L_0017: stloc.3 
      21:      L_0018: br.s L_003a
      22:      L_001a: ldloc.3 
      23:      L_001b: callvirt instance !0 [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::get_Current()
      24:      L_0020: stloc.2 
      25:      L_0021: nop 
      26:      L_0022: ldloc.2 
      27:      L_0023: ldc.i4.5 
      28:      L_0024: cgt 
      29:      L_0026: ldc.i4.0 
      30:      L_0027: ceq 
      31:      L_0029: stloc.s CS$4$0001
      32:      L_002b: ldloc.s CS$4$0001
      33:      L_002d: brtrue.s L_0039
      34:      L_002f: ldloc.1 
      35:      L_0030: ldloc.2 
      36:      L_0031: ldloc.2 
      37:      L_0032: mul 
      38:      L_0033: callvirt instance void [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
      39:      L_0038: nop 
      40:      L_0039: nop 
      41:      L_003a: ldloc.3 
      42:      L_003b: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
      43:      L_0040: stloc.s CS$4$0001
      44:      L_0042: ldloc.s CS$4$0001
      45:      L_0044: brtrue.s L_001a
      46:      L_0046: leave.s L_005a
      47:      L_0048: ldloc.3 
      48:      L_0049: ldnull 
      49:      L_004a: ceq 
      50:      L_004c: stloc.s CS$4$0001
      51:      L_004e: ldloc.s CS$4$0001
      52:      L_0050: brtrue.s L_0059
      53:      L_0052: ldloc.3 
      54:      L_0053: callvirt instance void [mscorlib]System.IDisposable::Dispose()
      55:      L_0058: nop 
      56:      L_0059: endfinally 
      57:      L_005a: nop 
      58:      L_005b: ldarg.0 
      59:      L_005c: ldfld class [System.Windows]System.Windows.Controls.ListBox PerfTest.MainPage::LB1
      60:      L_0061: ldloc.1 
      61:      L_0062: callvirt instance void [System.Windows]System.Windows.Controls.ItemsControl::set_ItemsSource(class [mscorlib]System.Collections.IEnumerable)
      62:      L_0067: nop 
      63:      L_0068: ret 
      64:      .try L_0018 to L_0048 finally handler L_0048 to L_005a
      65:  }
      66:   
      67:   

    Compare that to the IL generated for the LINQ version which has about half of the instructions and just gets the job done, no fluff.

       1:  .method private hidebysig instance void LINQMethod() cil managed
       2:  {
       3:      .maxstack 4
       4:      .locals init (
       5:          [0] class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> someData,
       6:          [1] class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> queryResult)
       7:      L_0000: nop 
       8:      L_0001: ldc.i4.1 
       9:      L_0002: ldc.i4.s 50
      10:      L_0004: call class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> [System.Core]System.Linq.Enumerable::Range(int32, int32)
      11:      L_0009: stloc.0 
      12:      L_000a: ldloc.0 
      13:      L_000b: ldsfld class [System.Core]System.Func`2<int32, bool> PerfTest.MainPage::CS$<>9__CachedAnonymousMethodDelegate6
      14:      L_0010: brtrue.s L_0025
      15:      L_0012: ldnull 
      16:      L_0013: ldftn bool PerfTest.MainPage::<LINQProgramming>b__4(int32)
      17:      L_0019: newobj instance void [System.Core]System.Func`2<int32, bool>::.ctor(object, native int)
      18:      L_001e: stsfld class [System.Core]System.Func`2<int32, bool> PerfTest.MainPage::CS$<>9__CachedAnonymousMethodDelegate6
      19:      L_0023: br.s L_0025
      20:      L_0025: ldsfld class [System.Core]System.Func`2<int32, bool> PerfTest.MainPage::CS$<>9__CachedAnonymousMethodDelegate6
      21:      L_002a: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Where<int32>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [System.Core]System.Func`2<!!0, bool>)
      22:      L_002f: ldsfld class [System.Core]System.Func`2<int32, int32> PerfTest.MainPage::CS$<>9__CachedAnonymousMethodDelegate7
      23:      L_0034: brtrue.s L_0049
      24:      L_0036: ldnull 
      25:      L_0037: ldftn int32 PerfTest.MainPage::<LINQProgramming>b__5(int32)
      26:      L_003d: newobj instance void [System.Core]System.Func`2<int32, int32>::.ctor(object, native int)
      27:      L_0042: stsfld class [System.Core]System.Func`2<int32, int32> PerfTest.MainPage::CS$<>9__CachedAnonymousMethodDelegate7
      28:      L_0047: br.s L_0049
      29:      L_0049: ldsfld class [System.Core]System.Func`2<int32, int32> PerfTest.MainPage::CS$<>9__CachedAnonymousMethodDelegate7
      30:      L_004e: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!1> [System.Core]System.Linq.Enumerable::Select<int32, int32>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [System.Core]System.Func`2<!!0, !!1>)
      31:      L_0053: stloc.1 
      32:      L_0054: ldarg.0 
      33:      L_0055: ldfld class [System.Windows]System.Windows.Controls.ListBox PerfTest.MainPage::LB2
      34:      L_005a: ldloc.1 
      35:      L_005b: callvirt instance void [System.Windows]System.Windows.Controls.ItemsControl::set_ItemsSource(class [mscorlib]System.Collections.IEnumerable)
      36:      L_0060: nop 
      37:      L_0061: ret 
      38:  }

    Again, not surprising here but a good indicator that you should consider using LINQ where possible. In fact if you have ReSharper installed you’ll see a squiggly (technical term) in the imperative code that says “Hey Dude, I can convert this to LINQ if you want to be c00L!” (or something like that, it’s the 2010 geek version of Clippy).

    What about the fluent version? As Jon correctly pointed out in the comments, when you compare the IL for the LINQ code and the IL for the fluent code it’s the same. LINQ and the fluent interface are just syntactical sugar so you decide what you’re most comfortable with. At the end of the day they’re both the same.

    Now onto the numbers. Again I expected the imperative version to be better performing than the LINQ version (before I saw the IL that was generated). Call it womanly instinct. A gut feel. Whatever. Some of the numbers are interesting though.

    For Jesse’s example of 50 items, the numbers were interesting. The imperative sample clocked in at 7ms while the LINQ version completed in 4. As the number of items went up, the elapsed time didn’t necessarily climb exponentially. At 500 items they were pretty much the same and the results were similar up to about 50,000 items. After that I tried 500,000 items where the gap widened but not by much (2.2 seconds for imperative, 2.3 for LINQ). It wasn’t until I tried 5,000,000 items where things were noticeable. Imperative filled the list in 20 seconds while LINQ took 8 seconds longer (although personally I wouldn’t suggest you put 5 million items in a list unless you want your users showing up at your door with torches and pitchforks).

    Here’s the table with the full results.

      </STRONG><TD vAlign="top" width="71"><STRONG>50</STRONG></TD><STRONG>
    
      </STRONG><TD vAlign="top" width="71"><STRONG>500</STRONG></TD><STRONG>
    
      </STRONG><TD vAlign="top" width="71"><STRONG>5,000</STRONG></TD><STRONG>
    
      </STRONG><TD vAlign="top" width="71"><STRONG>50,000</STRONG></TD><STRONG>
    
      </STRONG><TD vAlign="top" width="71"><STRONG>500,000</STRONG></TD><STRONG>
    
      </STRONG><TD vAlign="top" width="71"><STRONG>5,000,000</STRONG></TD>
    </TR>
    
    <TR>
      <TD vAlign="top" width="71">Imperative</TD>
    
      <TD vAlign="top" width="71">7ms</TD>
    
      <TD vAlign="top" width="71">7ms</TD>
    
      <TD vAlign="top" width="71">38ms</TD>
    
      <TD vAlign="top" width="71">223ms</TD>
    
      <TD vAlign="top" width="71">2230ms</TD>
    
      <TD vAlign="top" width="71">20974ms</TD>
    </TR>
    
    <TR>
      <TD vAlign="top" width="71">LINQ/Fluent</TD>
    
      <TD vAlign="top" width="71">4ms</TD>
    
      <TD vAlign="top" width="71">6ms</TD>
    
      <TD vAlign="top" width="71">41ms</TD>
    
      <TD vAlign="top" width="71">240ms</TD>
    
      <TD vAlign="top" width="71">2310ms</TD>
    
      <TD vAlign="top" width="71">28731ms</TD>
    </TR>
    
    Method/Items

    Like I said, at the end of the day it’s not a huge difference and you really don’t want your users waiting around for 30 seconds on a mobile device filling lists. In fact if Windows Phone 7 detects you’re taking more than 10 seconds to do any one thing, it considers the app hung and shuts it down. The results here are for Windows Phone 7 but frankly they're the same for desktop and web apps so feel free to apply it generally.

    From a programming perspective, choose what you like. Some LINQ statements can get pretty hairy so I usually fall back with my simple mind and write it imperatively. If you really want to impress your friends, write it old school then let ReSharper do the hard work for!

    Happy programming!

  • Generic Pop and Push for List<T>

    Here's a little snippet I use to extend a generic List class to have similar capabilites to the Stack class.

    The Stack<T> class is great but it lives in its own world under System.Object. Wouldn't it be nice to have a List<T> that could do the same? Here's the code:

       1:  public static class ExtensionMethods
       2:  {
       3:      public static T Pop<T>(this List<T> theList)
       4:      {
       5:          var local = theList[theList.Count - 1];
       6:          theList.RemoveAt(theList.Count - 1);
       7:          return local;
       8:      }
       9:   
      10:      public static void Push<T>(this List<T> theList, T item)
      11:      {
      12:          theList.Add(item);
      13:      }
      14:  }

    It's a simple extension but I've found it useful, hopefully you will too! Enjoy.

  • WP7 “Phantom Data” Source Possibly Revealed?

    Recently there’s been rumours floating around regarding “phantom” Windows Phone 7 data being magically sent and received on the latest WP7 phones. The news has mostly been floating around twitter so I didn’t pay it much attention. The BBC Technology News picked it up so I thought I would look more into it myself seeing that we have WP7 phones and maybe there was some truth to all this (and more importantly what was the cause).

    Full disclosure. I don’t have a lot of data points around this. This is from looking at a few phone logs, changing the configuration and looking back again after the change. I haven’t done a clean baseline test nor have I done testing with hundreds of phones. I leave the experience up to the reader to decide.

    So I went spelunking into the phone logs to see what was up. Most providers will show you data usage, at least on a daily basis. I lucked out with the provider and plan in that they provide hourly breakdowns. Here’s a snapshot from my usage throughout one night.

    Timestamp Data Usage
    12:38:30 AM 2098 Kilobytes
    1:30:30 AM 2 Kilobytes
    2:38:30 AM 7118 Kilobytes
    3:38:30 AM 6622 Kilobytes
    4:38:30 AM 76 Kilobytes
    5:38:30 AM 29 Kilobytes
    6:38:30 AM 19 Kilobytes
    7:38:30 AM 20 Kilobytes

    So a few observations from this data:

    • Data seems to be collected on a regular basis. Looking at some other people phone logs, the times vary but it’s always hourly.
    • There’s not a tremendous amount of data here (about 16 megabytes) but it seems like a lot for 7 hours
    • The phone was connected to my home Wifi during this period
    • Nothing was running and the phone was in a locked state

    Like I said, not a lot of data but it adds up. 16MB for 7 hours = about 50MB in a 24 hour period. That’s just plain old data being collected (somewhere, somehow) and not actual usage (Marketplace, Email, Browsing, etc.). Besides, when connected to a WiFi network you shouldn’t be charged data usage from your phone company (in theory, YMMV).

    After reviewing the logs I made a theory that the only thing that could possibly be sending data is the Feedback feature. With no other apps running under lock, what else could it be?

    In Windows 7 under your Settings the last option is Feedback. This sends feedback to Microsoft to “help improve Windows Phone”. On this page you have three options:

    • Send feedback and use my cellular data connection
    • Send feedback and (presumably) use my WiFi connection
    • Don’t send feedback

    Knowing what I know about Microsoft, they do use the feedback data. For example some of the placement and inclusion of features in Office 2007 was based on that Feedback data that Office sends (assuming you had opted in).

    However in the Privacy Statement (it’s long but a good read at least once in your life), the Phone manual, and every other source I could look at there is no information about how much data it’s planning to send, just that it’s sending some data and that “some data charges with your carrier may apply”.

    Looking back at the logs, I have to wonder. 6MB at 3:30 and *then* 7MB the next hour. That’s a lot of information. And it adds up. 50MB in a 24 hour period X 30 days puts most people over a normal 1GB plan. And frankly why am I paying for a data plan only to have 80% of it chewed up by Microsoft, with no real benefit to me. If they included porn in the 50mb daily transfer I’d be okay with this, but I don’t see any new movies on my phone.

    So I turned it off. Set Feedback to disabled and wait.

    I waited. And waited. And generally didn’t use the phone if I could.

    The next day I went back to look at the data usage logs from the time period after turning the feedback mechanism off. Here are the results.

    Timestamp Data Usage
    1:19:48 PM 0 Kilobytes
    2:19:48 PM 0 Kilobytes
    3:19:48 PM 0 Kilobytes
    4:19:48 PM 678 Kilobytes (took a phone call)
    5:19:48 PM 82 Kilobytes
    6:19:48 PM 88 Kilobytes
    7:20:30 PM 86 Kilobytes (guess they changed their reporting time)
    8:20:30 PM 86 Kilobytes
    9:20:30 PM 66 Kilobytes
    10:20:30 PM 67 Kilobytes
    11:20:30 PM 49 Kilobytes
    12:20:30 AM 32 Kilobytes
    1:20:30 AM 38 Kilobytes
    2:20:31 AM 18 Kilobytes
    3:20:31 AM 27 Kilobytes
    4:20:31 AM 86 Kilobytes
    5:20:31 AM 53 Kilobytes
    6:20:31 AM 22 Kilobytes
    7:22:15 AM 30 Kilobytes (another reporting time change)
    8:22:15 AM 29 Kilobytes
    9:22:15 AM 74 Kilobytes
    10:22:15 AM 154 Kilobytes (phone call)
    11:22:15 AM 12 Kilobytes
    12:13:27 PM 49 Kilobytes
    1:13:27 PM 197 Kilobytes (phone call)

    Quite a *drastic* change from what Feedback was turned on. I mean for a 24 hour period (sans 3 phone calls) I consumed about 1MB. Still quite a bit of transfer going on but at least it amounts to 30MB per month, not 30MB per day!

    Like I said this observation is neither scientific or conclusive. You decide what to do but frankly until Microsoft makes this data transfer exempt from your data plan (like that will happen) I would just turn Feedback off. YMMV.

  • Do’s and Don’ts Building SharePoint Applications

    SharePoint is a great platform for building quick LOB applications. Simple things from employee time trackers to server and software inventory to full blown Help Desks can be crafted up using SharePoint from just customizing Lists. No programming necessary. However there are a few tricks I’ve painfully learned over the years that you can use for your own solutions.

    DO

    What’s In A Name?

    When you create a new list, column, or view you’ll commonly name it something like “Expense Reports”. However this has the ugly effect of creating a url to the list as “Expense%20Reports”. Or worse, an internal field name of “Expense_x0x0020_Reports” which is not only cryptic but hard to remember when you’re trying to find the column by internal name.

    While “Expense Reports 2011” is user friendly, “ExpenseReports2011” is not (unless you’re a programmer). So that’s not the solution. Well, not entirely.

    Instead when you create your column or list or view use the scrunched up name (I can’t think of the technical term for it right now) of “ExpenseReports2011”, “WomenAtTheOfficeThatAreMen” or “KoalaMeatIsGoodWhenBroiled”. After you’ve created it, go back and change the name to the more friendly “Silly Expense Reports That Nobody Reads”. The original internal name will be the url and code friendly one without spaces while the one used on data entry forms and view headers will be the human version.

    Smart Columns

    When building a view include columns that make sense. By default when you add a column the “Add to default view” is checked. Resist the urge to be lazy and leave it checked. Uncheck that puppy and decide consciously what columns should be included in the view.

    Pick columns that make sense to what the user is trying to do. This means you have to talk to the user. Yes, I know. That can be trying at times and even painful. Go ahead, talk to them. You might learn something.

    Find out what’s important to them and why. If they’re doing something repetitively as part of their job, try to make their life easier by including what’s most important to them. Do they really need to see the Created *and* Modified date of a document or do they just need the title and author? You’ll only find out after talking to them (or getting them drunk in a bar and leaving them in the back alley handcuffed to a garbage bin, don’t ask).

    Gotta Keep it Separated

    Hey, views are there for a reason. Use them. While “All Items” is a fine way to present a list of well, all items, it’s hardly sufficient to present a list of servers built before the Y2K bug hit. You’ll be scrolling the list for hours finally arriving at Page 387 of 12,591 and cursing that SharePoint guy for convincing you that putting your hardware into a list would be of any use to anyone.

    Next to collecting the data, presenting it is just as important. Views are often overlooked and many times ignored or misused. They’re the way you can slice and dice the data up so that you’re not trying to consume 3,000 years of human evolution on a single web page.

    Remember views can be filtered so feel free to create a view for each status or one for each operating system or one for each species of Information Worker you might be putting in that list or document library. Not only will it reduce the number of items someone sees at one time, it’ll also make the information that much more relevant.

    Also remember that each view is a separate page. Use it in navigation by creating a menu on the Quick Launch to each view. The discoverability of the Views menu isn’t overly obvious and if you violate the rule of columns (see Horizontally Scrolling below) the view menu doesn’t even show up until you shuffle the scroll bar to the left. Navigation links, big giant buttons, a screaming flashing “CLICK ME NOW” will help your users find their way.

    Sort It!

    Views are great so we’re building nice, rich views for the user. Awesomesauce. However sort is not very discoverable by the user. For example when you’re looking at a view how do you know if it’s ascending or descending and what is it sorted on. Maybe it’s sorted using two fields so what’s that all about?

    Help your users by letting them know the information they’re looking at is sorted. Maybe you name the view something appropriate like “Bogus Expense Claims Sorted By Deadbeats”. If you use the naming strategy just make sure you keep the name consistent with the description. In the previous example their better be a Deadbeat column so I can see the sort in action. Having a “Loser” column, while equally correct, is a little obtuse to the average Information Worker. Remember, they usually don’t use synonyms and even if they knew how to, it’s not immediately obvious to them that’s what you’re trying to convey.

    Another option is to simply drop a Content Editor Web Part above the list and explain exactly the view they’re looking at. Each view is it’s own page so one CEWP won’t be used across the board. Be descriptive in what the user is seeing but try to keep it brief. Dumping the first chapter of I, Claudius might be informative to the data but can gobble up screen real estate and miss the point of having the list.

    DO NOT

    Useless Attachments

    The attachments column is, in a word, useless. For the most part. Sure it indicates there’s an attachment on the list item but in the grand scheme of things that’s not overly informative. Maybe it is and by all means, if it makes sense to you include it. Colour it. Make it shine and stand like the Return of Clippy on every SharePoint list.

    Without it being functional it can be boring. EndUserSharePoint.com has an article to make the son of Clippy that much more useful so feel free to head over and check out this blog post by Paul Grenier on the task (Warning code ahead! Danger Will Robinson!)

    In any case, I would suggest you remove it from your views. Again if it’s important then include it but consider the jQuery solution above to make it functional. It’s added by default to views and one of things that people forget to clean up.

    Horizontal Scrolling

    Screen real estate is premium so building a list that contains 8,000 columns and stretches horizontally across 15 screens probably isn’t the most user friendly experience. Most users can’t figure out how to scroll vertically let alone horizontally so don’t make it even that more confusing for them. Take the Steve Krug approach in your view designs and try not to make the user think.

    Again views are your friend. Consider splitting up the data into views where one view contains 10 columns and other view contains the other 10. Okay, maybe your information doesn’t work that way but humans can only process 7 pieces of data at a time, 10 at most (then their heads explode and you don’t want to clean that mess up, especially on a Friday night before the big dance).

    It drives me batshit crazy when I see a view with 80 columns of data. I often ask the user “So what do you do with all this information”. The response is usually “With this data [the first 10 columns] I decide if I’m going to fire everyone, and with this data [the next 10 columns] I decide if I’m going to set the building on fire and collect the insurance”. It’s at that point I show them how to create two new views “People Who Are About To Get The Axe” and “Beach Time For The Executives”. Again, talk to your users and try to reason with them on cutting down the number of columns they see at once.

    Vertical Scrolling

    Another big faux pas I find is the use of multi-line comment fields in views. It’s not so bad when you have a statement like this in your view:

    “I really like, oh my god, thought I was going to scream when I saw this turtle then I decided what I was going to have for dinner and frankly I hate having to work late so when I was talking to the customer I thought, oh my god, what if the customer has turtles and then it appeared to me that I really was hungry so I'm going to have lunch now.”

    It’s fine if that’s the only column along with two or three others, but once you slap those 20 columns of data into the list, the comment field wraps and forms a new multi-page novel that takes up your entire screen.

    Do everyone a favour and just avoid adding the column to views. Train the user to just click through to the item if they need to see the contents.

    Duplicate Information

    Duplication is never good. Views and great as you can group data together. For example create a view of project status reports grouped by author. Then you can see what project manager is being a dip and not submitting their report. However if you group by author do you really need the Created By field as well in the view? Or if the view is grouped by Project then Author do you need both.

    Horizontal real estate is always at a premium so try not to clutter up the view with duplicate data like this. Oh  yeah, if you’re scratching your head saying “But Bil, if I don’t include the Project name in the view and I have a lot of items then how do I know which one I’m looking at”. That’s a hint that your grouping is too vague or you have too much data in the view based on that criteria. Filter it down a notch, create some views, and try to keep the group down to a single screen where you can see the group header at the top of the page. Again it’s just managing the information you have.

    Redundant, See Redundant

    This partially relates to duplicate information and smart columns but basically remember to not include the obvious in a view. Remember, don’t make me think. If you’ve gone to the trouble (and it was a lot of trouble wasn’t it?) to create separate views of your data by creating a “September Zombie Brain Sales”, “October Zombie Brain Sales”, etc. then please for the love of all that is holy do not include the Month and Product columns in your view. Similarly if you create a “My” view of anything (“My Favourite Brands of Spandex”, “My Co-Workers I Find The Urge To Disinfect”) then again, do not include the owner or author field (or whatever field you use to identify “My”). That’s just silly.

    Hope that helps! Happy customizing!