Thursday, November 29, 2012

A bad way to set up commands in your view model

tl;dr; Put code where it is defined. It makes maintenance much easier.

This has become a bit of a pet-peeve of mine lately. Please indulge me while I share.

I spend a lot of time working with code that was started by someone else.
As MVVM Light is used in most projects I work on, I see code that looks like this a lot:

    public class MyViewModel : ViewModelBase
    {
        public MyViewModel()
        {
            MyCommand = new RelayCommand(() =>
            {
               // some functionality here
            });
        }
        
        public RelayCommand MyCommand { get; private set; }
    }
This bugs me.
Seeing this just makes me think that the original developer was planning on allowing for the possibility that they may want to change what the command does at some point in the future.
But I haven't seen any code that actually does that, yet.

Remember Y.A.G.N.I.
I think this is much better:
    public class MyViewModel : ViewModelBase
    {
        public MViewyModel()
        {
        }
        
        public RelayCommand MyCommand 
        { 
            get
            {
                return new RelayCommand(() =>
                {
                    // some functionality here
                });
            }
        }
    }
 
And you probably don't really need the empty constructor. (I know in this instance you don't but depending on what else is being done in the VM you might.)
There is no difference in the actual number of lines of code or functionality but it's much better.

Why do I think this is better?

It puts the actual code where it is defined and so when I identify the command I'm after I can see what it does.
Putting the code where it is defined means it's easier to navigate the code when you aren't familiar with it.

Let's say I need to change (or fix) some behaviour that is triggered via a command. I'll start in the view (the UI) which uses/triggers that command. From there I can easily see where the command is defined (Ctrl + Click : with ReSharper). That's good, but if the code isn't there I have to search the code ("Find Usages" or "Find References") and then go to where I think it's most likely to be based on what I can see in the search results.
I've had to, unnecessarily, go hunting around the code for what I want.
The code I'm looking for has been hidden!
That's not a good way to treat the people who will be maintaining the code you wrote.

Not wanting to make any claims about my mental health and disposition but:
"Always code as if the person who ends up maintaining your code is a violent psychopath who knows where you live."


Am I missing something by doing this my way?
Does the maintainability benefit come at some other cost?

Obviously there are exceptions to the above and times when you may not want to have a readonly command. My point is to think about the code you're writing and the people who will be maintaining it and trying to work out what it does. The easier you can make this for them the less frustrated with you they'll get. :)



Do emulators have value if we still have to test on actual devices.?

This is in response to a comment on my post about the undocumented way I found of creating a xap file you can't deploy to a #wp8 device.

In that post I claimed that it was important to test on physical devices as well as in the emulator. The comment stated
"this seems to break the whole "emulator" thing, since it seems that it doesn't properly emulate a physical device!"

Firstly, I'm not aware of anyone ever claiming that an emulator completely does away with the need for testing on real devices.
I've only heard people claim you MUST test on physical hardware in addition to an emulator/simulator. This goes back many, many years and has always been essential for phones as emulators have never given a complete representation of actual devices. They've gotten a lot better but by their very nature they're not perfect.

This is important:
An emulator (or simulator) emulates (or simulates) a real device. It doesn't claim to give a complete representation of a real device.

What is an emulator actually good for then?

  • Testing quickly
  • Testing multiple devices or configurations and switching between them quickly
  • Automated testing
  • Testing before devices are available.
  • Testing on devices you can't buy (due to financial or location restrictions) - but beware that this means you won't know about the experience of the app on those devices. This may or may not be an issue.
  • Avoiding issues with the number of side-loaded apps installed on an actual device. (Or maybe I just need to keep track of what I side-load better)
  • Testing use in different locations (without needing to create your own mocking layer)
  • Testing use of the accelerometer (without needing to create your own mocking layer)
  • Testing different network conditions (network speed & signal strength) - again without having to create your own mocking layer.
  • Testing app behaviour when reminders are triggered.


What must you test on an actual device?

  • What it's really like to use the app in the hand (your thumb and a mouse pointer are not the same!)
  • What the actual performance is like on actual devices
  • Any functionality that isn't available in the emulator (interruption from incoming phone calls, etc.)
  • That the behaviour of the app on an actual device is the same as the emulator.

This list assumes use of VS2012 for testing Windows Phone (8) apps. For other platforms and emulators/simulators the above lists may vary slightly.

Wednesday, November 28, 2012

Why "scratching your own itch" is a bad idea for developers

There's a popular idea that if you have a need for something then it's likely that other people will too. It's often termed "scratching your own itch".

Developers like to take this idea and assume that if there's something they need or want and build an app to meet that scenario others will also buy that app to meet the same need.

I think this view ignores a big issue.
The "others" in this scenario are typically other developers, and developers like writing code to solve their own problems.
The corollary of this is that developers don't look to buy solutions written by other developers to solve their problems.

Yes this is a huge generalisation but I believe it also holds a lot of truth. Just ask a developer you know how often they buy solutions to their problems verses writing their own solutions.

The mis-assumption is that other developers will buy their app as they have the same problem because they are just like them. The problem is that just like them the other developers will be creating their own apps to solve the same problem.

Developers building small apps for other developers isn't a great way to find a big market and sell lots of apps.
By all means build such apps just don't get upset if you don't get millions of downloads.



Tuesday, November 27, 2012

An undocumented way of creating a xap file you can't deploy to a #wp8 device

"Deployment failed" it's not a message you want to see when deploying your app to a device. Especially if you've previously deployed to the emulator without issue.

Even more worrying is this message:
"Deployment optimization failed due to an invalid assembly. Rebuild your source projects and try again."
Especially worrying after rebuilding several times.

A little googling for that message turns up the fact that this is also the error message displayed when trying to use the, now removed, WP8 version of the ReactiveExtensions but not a lot else. (As referenced at http://social.msdn.microsoft.com/Forums/en-US/rx/thread/ec22cacb-a996-4244-83ca-fe3b1d5ac5ff  and reported http://blogs.msdn.com/b/rxteam/archive/2012/11/14/update-on-windows-phone-8-support-for-rx-v2-0.aspx.)



It turns out that this was a result of an issue caused by a workaround after moving to TFS in the cloud.

Before moving to the cloud we had a powershell script which would rename the XAP file to include the version number of the main assembly. (This is invaluable during testing when you want to know you're installing the right version.)
Unfortunately this didn't work on the server.
Plan B was to use a simple command line app to rename the XAP instead.(It seems you can run [console] apps on the build server - but presumably with very little functionality actually available.)
To ensure that the exe was in the appropriate output directory I added it the project, set it's build action to None and set it to always copy to the output directory. This was the problem. The WP8 (this problem didn't happen in the WP7 version) compiler was seeing that there was an EXE in the project and doing something different with the final XAP.


Fortunately, this was resolved by adding the EXE to the solution directory and then referring to it from there without adding it to the project. The after build event still knows where everything is and all is good.


TL;DR/Lesson: Don't include desktop EXEs in your WP8 project, even if they're not included in the XAP.
And be sure to always test on actual devices, not just the emulator. It is possible for apps to run in the emulator and not even load on an actual device.

Background agent expiry in Windows Phone 8

In Windows Phone 7[.x] background agents would expire (stop working/running) if an app wasn't launched for 14 days. Today I noticed in MSDN that things are slightly different in Windows Phone 8:
There are a few cases where an app’s background agent will not expire or will be automatically renewed.
•   If the Tile for your app is pinned to the phone’s Start screen, the expiration time for your background agent schedule is automatically extended to two weeks whenever your background agent calls Update(ShellTileData) to update the Tile.
•   If your app is selected by the user to display notifications on the on the lock screen, the expiration time for your background agent schedule is automatically extended to two weeks whenever your background agent calls Update(ShellTileData) to update the lock screen.
•   If your app auto-uploads photos using a resource-intensive agent, the resource-intensive agent schedule will not expire as long as the user has enabled this feature for your app in the photos+camera settings page.

Monday, November 26, 2012

Spinning my nodes #AlphaLabsCC

Hold the phone. I've been actually having fun writing XNA!
Ok, there was some head scratching getting some of the maths right but I got there.

Circles were boring.
Now I have spirals. And although you can't see it in these pictures they spin.


It's quite hypnotic to watch when animated.

The spirals (nodes) vary in direction of rotation, size and speed of rotation.


Saturday, November 24, 2012

Node Garden + multiple colours + transparencies #AlphaLabsCC

I've been playing with transparencies and multiple colours of node.
The screenshot below gives an idea but when animated it can create some really nice effects.

Best of all this only required adding a few lines of code. Plus I got to delete a load of other code I didn't need. - Deleting code is always good. :)

I'm looking forward to exploring other visual ideas.

This was done with Silverlight, but as the HTML version of the demo code is now available, I might look at using that for my next itteration.


Thursday, November 22, 2012

Passing additional information between nodes #AlphaLabsCC

As promised, here's an example of how to pass additional information between nodes/devices as part of your AlphaLabs projects.

I'm going to show how to pass the color of the current node to other devices, along with it's position, so that instead of just having your own node coloured and all other nodes white, every node is represented by the theme colour of the device it is actually on.
I'm also going to show how to do this with the Silverlight version as I'm assuming that everyone will be able to follow along with that without issue.
Something like this:

Obviously this makes it harder to tell which is your own node (hint, in the base code it's slightly larger than the others) but I'm sure you can cope and come up with interesting and exciting ways of indicating this in your apps/experiments/art.

So how do we do this?

It's all down to the power of the Tag!
I'm sure you're familiar with the Tag property of a Control or FrameworkElement. It's a useful miscellaneous property for storing arbitrary information in an object. Well, NodeGardenLib.Node has one too. The only difference is that in the Node it's a string, not an object.

We can add anything (within reason) to this property and it can be passed between devices via the underlying messaging functionality.

We'll start by setting the Tag when we create the node.
In MainPage.xaml.cs:
        private void CreateOwnNode()
        {
            var myNode = new MyVisualNode(this.rand, MainCanvas, this.gardener);

            this.gardener.AddSelfNode(myNode.X, myNode.Y);

            myNode.Id = this.gardener.GetSelfNodeId();

            var accentColor = (Color)Application.Current.Resources["PhoneAccentColor"];
            myNode.Tag = accentColor.Serialize();

            this.nodes.Add(myNode);
        }

You'll notice I'm using a helper method to abstract the serialization. Here are all the helper methods I'm using:

    using System;
    using System.Windows.Media;

    using Newtonsoft.Json;

    public static class ColorExtensions
    {
        public static string Serialize(this Color source)
        {
            return JsonConvert.SerializeObject(source);
        }
    }

    public static class StringExtensions
    {
        public static Color DeserializeAsColor(this string source)
        {
            try
            {
                return JsonConvert.DeserializeObject<color>(source);
            }
            catch (Exception exc)
            {
                return Colors.White;
            }
        }

        public static Brush DeserializeAsBrush(this string source)
        {
            return new SolidColorBrush(source.DeserializeAsColor());
        }
    }

I'm using Json.Net for the serialization as it's already referenced (as a dependency of SignalR) but you could use whatever you want.
The other important point of note is that I have exception handling in the Deserialize[AsColor] method. This is REALLY important as we may be receive messages from apps on other devices and they may be sending different, or no, information in the Tag. Be sure to handle deserialization exceptions and never make assumptions about what you'll receive.
This is of minor issue when you're only connecting to your own devices as it's easy to tell when not all devices are running the same version of the app-that's why the version number is auto-generated and displayed on the debug/config page.
It becomes more of an issue when connecting to the internet and anyone else is running a version of the app and also connecting to the internet as you'll be notified of each others nodes.

BTW: Always connect via the web option unless you really, really have a good reason to use UDP.
This is for 2 reasons: 1. We get to track what you're doing as everything that goes via the web is logged. (We'll make all the logged data available at the end of the project.) And 2. It's cool when other nodes (representing real other people/devices) appear in your garden.

Once we've got the color information in the tag we have to make sure we send it. So update MyVisualNode.cs:
this.gardener.UpdateSelfNodePosition(this.X, this.Y, this.Tag);

Then we need to make sure that we use the received color when drawing nodes.
In the Draw method of VisualNode.cs add:
this.NodeSize = Map(normalisedConnectedness, 0, 1, NodeSizeMin, this.NodeSizeMax());

this.Center.Fill = this.Tag.DeserializeAsBrush();
this.Center.Width = this.NodeSize;
this.Center.Height = this.NodeSize;


Simples.
Now just fire up a couple of emulators and voila:

If you try this over Web comms you'll notice that other nodes don't show up until they're moved. I think this is because of the way the WIEB (Where Is EveryBody) message is handled. Let me know if this is a big issue for you. Or fix it and send me a patch. ;)



But what if we want to test this easily without deploying to lots of devices? We'll just update the default nodes-that's what they're there for.

So in MainPage.xaml.cs

private void CreateDefaultNodes(int numberOfNodes)
{
    for (int i = 0; i < numberOfNodes; i++)
    {
        var visualNode = new VisualNode(this.rand, MainCanvas);
        visualNode.Tag = this.RandomAccentColor(this.rand).Serialize();

        this.nodes.Add(visualNode);
    }
}

private Color RandomAccentColor(Random random)
{
    // via http://chemicaloli.net/2011/10/01/windows-phone-7-accent-colour-list/
    switch (random.Next(1, 10))
    {
        case 1: return new Color { A = 255, R = 27, G = 161, B = 226 }; // Blue
        case 2: return new Color { A = 255, R = 160, G = 80, B = 0 }; // Brown
        case 3: return new Color { A = 255, R = 51, G = 153, B = 51 }; // Green
        case 4: return new Color { A = 255, R = 230, G = 113, B = 184 }; // Pink
        case 5: return new Color { A = 255, R = 162, G = 0, B = 255 }; // Purple
        case 6: return new Color { A = 255, R = 229, G = 20, B = 0 }; // Red
        case 7: return new Color { A = 255, R = 0, G = 171, B = 169 }; // Teal
        case 8: return new Color { A = 255, R = 162, G = 193, B = 57 }; // Lime
        default: return new Color { A = 255, R = 216, G = 0, B = 115 }; // Magenta
    }
}

The above is all quite trivial but hopefully shows how easy it is to send additional information. You can send ANYTHING so don't let yourself be limited by just thinking you're limited to accent colours.

Now go. And be creative...

Wednesday, November 21, 2012

Important #AlphaLabsCC update

If you're involved in the current Alphalabs project (The Always-on Telephone Club) then you'll need to go grab the latest code from codeplex as I've just pushed an important fix. (changeset 17283)

This changeset includes the ability to include additional, arbitrary, information in the message that is sent between devices. Without this it's much harder to do interesting things.

I'll post an explanation of how to use it shortly.

The fact I shipped this and hadn't spotted it until now was a big error on my part.
I'm sorry.
Please forgive me.