Think before you animate

Animations are becoming more and more common in our applications.  With technologies like WPF, Silverlight and jQuery, animations are becoming easier for developers to use (and abuse).  When used properly, animation can augment the user experience.  When used improperly, animation can degrade the user experience.  Sometimes, the differences can be very subtle.

I have recently made use of animations in a few projects and I very quickly realized how easy it is to abuse animation techniques.  Here are a few things I have learned along the way.

1) Don’t animate for the sake of animating

We’ve all seen the PowerPoint slides with annoying slide transitions that animate 20 different ways.  It’s distracting and tacky.  The same holds true for your application.  While animations are fun and becoming easy to implement, resist the urge to use the technology just because you think the technology is amazing.

 

2) Animations should (and do) have meaning

I recently built a simple Windows Phone 7 (WP7) application, Steeped (download it here).  The application has 2 pages.  The first page lists a number of tea types.  When the user taps on one of the tea types, the application navigates to the second page with information about that tea type and some options for the user to choose from. 

Screenshot1     Screenshot2

One of the last things I did before submitting Steeped to the marketplace was add a page transition between the 2 pages.  I choose the Slide / Fade Out transition.  When the user selects a tea type, the main page slides to the left and fades out.  At the same time, the details page slides in from the right and fades in.  I tested it and thought it looked great so I submitted the app.  A few days later, I asked a friend to try the app.  He selected a tea type, and I was a little surprised by how he used the app.  When he wanted to navigate back to the main page, instead of pressing the back button on the phone, he tried to use a swiping gesture.  Of course, the swiping gesture did nothing because I had not implemented that feature. 

After thinking about it for a while, I realized that the page transition I had chosen implied a particular behaviour.  As a user, if an action I perform causes an item (in this case the page) to move, then my expectation is that I should be able to move it back.  I have since added logic to handle the swipe gesture and I think the app flows much better now.

When using animation, it pays to ask yourself:  What story does this animation tell my users?

 

3) Watch the replay

Some animations might seem great initially but can get annoying over time.  When you use an animation in your application, make sure you try using it over and over again to make sure it doesn’t get annoying.  When I add an animation, I try watch it at least 25 times in a row.  After watching the animation repeatedly, I can make a more informed decision whether or not I should keep the animation.  Often, I end up shortening the length of the animations.

 

4) Don’t get in the users way

An animation should never slow the user down.  When implemented properly, an animation can give a perceived bump in performance.  A good example of this is a the page transitions in most of the built in apps on WP7.  Obviously, these page animations don’t make the phone any faster, but they do provide a more responsive user experience.  Why?  Because most of the animations begin as soon as the user has performed some action.  The destination page might not be fully loaded yet, but the system responded immediately to user action, giving the impression that the system is more responsive.  If the user did not see anything happen until after the destination page was fully loaded, the application would feel clumsy and slow.  Also, it is important to make sure the animation does not degrade the performance (or perceived performance) of the application.

 

Jut a few things to consider when using animations.  As is the case with many technologies, we often learn how to misuse it before we learn how to use it effectively.

Deal Groupie – Learning WP7 and ASP.NET MVC 3

Lately, I have been taking some time to learn some new technologies.  For me, the best way to learn a new technology is to jump head first into a project:

Daily deal websites such as GroupOn, LivingSocial, DealFind, etc. have really taken off over the last 6 months.  With so many sites out there, my inbox was being flooded with emails from all these daily deal websites.  This seemed like it might be a fun project,  so I set out to build a daily deal aggregator.

First, I built a Windows Phone 7 app.  I built this app using Visual Studio 2010. Silverlight for WP7, the silverlight toolkit for WP7 and WCF.  Overall, I was pleased with the developer tools for Windows Phone 7 and I am looking forward to building more apps for WP7

ScreenShot5

The app conveniently presents deals for your city in a format very similar to the email client for Windows Phone 7.  Users can flag deals, share deals with friends, and buy deals from over 20 daily deal websites.  If you have a Windows Phone, you can download the Deal Groupie App here.

 

Next, I set out to learn some new web technologies.  I had recently attended a Microsoft Web Camp in Calgary (presented by Jonathan McCracken) and I was impressed with what I saw.  I decided to build a web version of Deal Groupie using ASP.NET MVC3.  I also made use of jQuery, jQuery UI, SQL Server CE 4 and WCF.  Since I had most of the backend already built, the web version did not take me nearly as long to build as the WP7 version did.  I spent more time tweaking the css than anything else.  The website provides daily deals for the selected city in 3 ways: a simple webpage listing all the active deals, a free daily email, and an RSS feed.  The RSS feed was exceptionally easy to implement using Syndication mechanism built in to WCF.

DealGroupieSite

Find deals in your city – http://www.mydealgroupie.com/

Currently, Deal Groupie is finding more than 2000 deals per day in over 300 cities in the USA, Canada, UK, and Australia.

Overall, building the Deal Groupie app and website has been a really good learning experience.  What’s next?  I’m thinking of building an Android version of the app and adding some filtering options to the website.

WF4 Asynchronous Workflows

If you are like me, you may have been surprised when you read the MSDN documentation for System.Activities.Statements.Parallel.

A Parallel activity operates by simultaneously scheduling each Activity in its Branches collection at the start. It completes when all of its Branches complete or when its CompletionCondition property evaluates to true. While all the Activity objects run asynchronously, they do not execute on separate threads, so each successive activity only executes when the previously scheduled activity completes or goes idle. If none of the child activities of this activity go idle, this activity execute in the same way that a **Sequence** activity does.

-MSDN (http://msdn.microsoft.com/en-us/library/system.activities.statements.parallel.aspx)

While the name implies that each branch of activities would be executed on a separate thread, the Parallel activity does not execute activities on separate threads.  In fact, all activities in a workflow execute on the same thread.  This is very similar to how in Windows Forms and WPF, all code that manipulates the user interface must be executed on the UI thread.  You might be asking yourself:  What is the point of this parallel activity?

It is possible for some activity to execute work on a background thread.  When combined with the Parallel activity (or the ParallelForEach activity), this allows the workflow runtime to schedule other activities to be executed while it is waiting for the background thread to complete.  WF4 comes with a number of asynchronous activities that can be used in this way.  Some examples are the Delay, InvokeMethod (when RunAsynchronously is set to true).  If you are creating custom activities, you can also create activities that execute asynchronously.  If you are implementing a code-based activity, you can inherit from AsyncCodeActivity.  If you are implementing more complex activities that need to make use of the workflow runtime, there are a couple strategies for implementing asynchronous activities.  One option is to use the parallel extensions introduced in .NET 4 (Workflow and Parallel Extensions).   Another option is to use bookmarks.

However, if you want to compose a workflow in XAML and have that workflow executed in parallel, your options are more limited.  Here’s an example:

In this example, I would like the 2 workflows to execute on a separate thread.  The output, however, shows that both activities are executed on the same thread:

Luckily, there is a way to accomplish this using a dynamic activity to execute a child activity on a background thread.  The child activity can be any activity (including Sequence or FlowChart), so this allows us to execute any portion of a workflow on a background thread. 


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using System.Threading.Tasks;
using System.ComponentModel;
using Microsoft.VisualBasic.Activities;

namespace ParallelActivities
{
[Designer(typeof(AsyncActivityWrapperDesigner))]
public class AsyncActivityWrapper : AsyncCodeActivity
{
public AsyncActivityWrapper()
{
Body = new ActivityAction();
}

    [Browsable(false)]
    public ActivityAction Body { get; set; }

    protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
    {        
         Activity activity = CreateDynamicActivity(context);
        IDictionary inputs = GetArgumentsAndVariables(context);
        Task task = Task.Factory.StartNew((ignore) =>
        {
            WorkflowInvoker.Invoke(activity, inputs);

        }, state);
        task.ContinueWith((t) => callback(t));
        return task;
    }

    protected override void EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
    {            
    }

    private Activity CreateDynamicActivity(AsyncCodeActivityContext context)
    {
        DynamicActivity result = new DynamicActivity();
        //Create a DynamicActivityProperty for each argument / variable in the current context
        foreach (PropertyDescriptor property in context.DataContext.GetProperties())
        {
            DynamicActivityProperty dynamicActivityProperty = new DynamicActivityProperty();

            dynamicActivityProperty.Name = property.Name;
            dynamicActivityProperty.Type = typeof(InArgument<>).MakeGenericType(property.PropertyType);
            dynamicActivityProperty.Value = Activator.CreateInstance(dynamicActivityProperty.Type);
            result.Properties.Add(dynamicActivityProperty);
        }

        //Copy impors to dynamic activity;
        VisualBasic.SetSettings(result, VisualBasic.GetSettings(this));
        result.Implementation = () => Body.Handler;
        return result;
    }

    private IDictionary GetArgumentsAndVariables(AsyncCodeActivityContext context)
    {
        IDictionary result = new Dictionary();

        foreach (PropertyDescriptor property in context.DataContext.GetProperties())
        {
            result.Add(property.Name, property.GetValue(context.DataContext));
        }

        return result;
    }
}

}

Using the AsyncActivityWrapper inside a Parallel activity accomplishes the desired behavior by executing activities inside the AsyncActivityWrapper as shown here:

With the AsyncActivityWrapper, we can see that each branch of the Parallel activity is executed on a separate thread:

The designer for this activity is actually very simple.  It contains a single WorkfowItemPresenter which allows us to drag and drop an activity into the AsyncActivityWrapper.


<sap:ActivityDesigner x:Class="ParallelActivities.AsyncActivityWrapperDesigner"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
    xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation">

    <sap:WorkflowItemPresenter Margin="7" Item="{Binding Path=ModelItem.Body.Handler, Mode=TwoWay}" HintText="Drop Activity"/>

</sap:ActivityDesigner>

In conclusion, the AsyncActivityWrapper can be used to execute portions of a workflow on a separate thread.  When combined with the Parallel or ParallelForEach activities, this allows us to execute multiple activities in parallel.  In situations where a workflow is processing a large amount of data, or doing a large number of complex calculations, the AsyncActivityWrapper can help to improve performance.  The implementation provided here does have some limitations.  As with any parallel programming, you need to make sure that activities that are executing in parallel do not conflict with each other.  If the activities are trying to access and manipulate the same data, you might run into problems.  If the activities have a return value, you may need an alternate implementation of AsyncActivityWrapper that inherits from AsyncCodeActivity<TResult>.  Also, since each activity is being executed as a separate independant workflow, you will lose some workflow functionality such as Persistence and Tracking.

Take the WF4 Speed Test

One of my previous posts talked about the performance improvements in WF4.  With the recent release of Visual Studio 2010 / .NET 4 RC1, I thought I would re-run my performance tests to see if there have been any further improvements with the most recent version.

My test is simply timing how long it takes to invoke an empty workflow (an Sequence activity that does nothing) 2,000,000 times.  This test gives us a good idea of the overhead of invoking a workflow.  With .NET 4.0 RC1, I am able to invoke ~275,000 workflows per second (approximately 15% faster than .NET 4 Beta 2).  I’m glad to see that Microsoft has continued to work on improving the performance of WF4. 

Take the WF4 speed test on your computer and let me know your results.  Create a new console application and past in the code below.  Don’t run the speed test in Visual Studio.  Compile the application and run the executable from outside Visual Studio.


using System;
using System.Linq;
using System.Activities;
using System.Activities.Statements;

namespace WFSpeedTest
{
class Program
{
static void Main(string[] args)
{
Activity activity = new Sequence();
WorkflowInvoker invoker = new WorkflowInvoker(activity);
DateTime startTime = DateTime.Now;
int numberOfInvokes = 2000000;
for (int i = 0; i < numberOfInvokes; i++)
{
invoker.Invoke();
}
DateTime endTime = DateTime.Now;
double workflowsPerSecond = numberOfInvokes / (endTime - startTime).TotalSeconds;
Console.WriteLine("Your WF Speed: {0} workflows per second", workflowsPerSecond);
Console.WriteLine("Press to exit…");
Console.ReadLine();
}
}
}

WF4 RC1, now 15% faster than WF4 Beta 2!

Adding Workflows in VS 2010

In Visual Studio 2010 Beta 1, you specifically selected if you were adding a Sequential Workflow or a Flowchart Workflow to your project.  In Visual Studio 2010 Beta 2, everything is an activity.  Instead of adding specific types of workflows to your project, you add an Activity.

In the Workflow Designer, you then drag either a Sequence activity or a Flowchart activity to the activity you just created.  This might seem like a small difference, but this really improves the composability of workflows in WF4.  Since workflows are no different than activities, we can compose a workflow of other workflows.  It also allows us to execute custom activities in unit tests without needing to create a workflow that wraps that activity (see previous post).

WF4 Performance

I have been playing around with the idea of modeling business rules as a set of small workflows (Flowcharts in WF4).  In the application, this would result in small workflows being called a large number of times.  I decided to investigate the performance overhead of invoking a workflow in WF4, the workflow technology in .NET 4.  Since I am using Visual Studio 2010 Ultimate Beta 2, this also seemed like a good opportunity to evaluate the performance profiler included in this edition of VS 2010.

For this test, I implemented a simple application that performs a calculation 10,000 times, then outputs that value to the console.  As a reference, I first implemented this in simple C# code as follows:

Code1

To determine the performance, I used the Instrumentation Profiler.  The simple C# code took approximately 800 milliseconds to execute.  Most of the time was spent writing to the console.

Profile1

 

Next, I implemented the calculation functionality in a simple flowchart workflow.  My flowchart has a single InArgument y, and an OutArgument x.

Workflow

In the Main method for my application, I modified the loop to call the simple workflow to perform the calculation.

Code2

The performance from this implementation seems a little disappointing at first.  We went from a total execution time of less than 1 second to approximately over 36 seconds.

Profile2

But if we really think about what’s happening here, this performance isn’t that bad.  We know that it takes about 1 second to perform the calculations and output the results.  That means that the remaining 35 seconds was spent on “workflow” related processing.  In that 35 seconds, we were able to create and execute 10,000 workflows.  Clearly this is not fast enough to accomplish what I was originally trying to do.

After digging through the profiler, I noticed that the application seemed to be spending a large percentage of the time initializing the workflow.  This led me to investigate if we could just create the workflow object one time and reuse it whenever we invoke that workflow.  It turns out that we can, and the results are dramatic.

 

The code is as follows:

Code4

Notice that I am now passing the input to the workflow using a Dictionary<string,object>.  I’m not sure why, but when I tried setting the input using workflow.y = i, the workflow would always use the first value that was assigned to y.  In this case, my output was always 0 because the workflow was always using y=0.  Passing the workflow inputs as a Dictionary seems to work around this problem.

Using this method of invoking the workflow, the total execution time was just over 1.15 seconds.

Profile4

Now this looks much better.  By caching the instance of the workflow object, we are able to significantly reduce the overhead of executing a workflow.  In this case, we spent just over 1/2 the time calling Console.WriteLine().  That means we were able to execute 10,000 workflows in the remaining .65 seconds.  Considering the flexibility this can provide in an application, I would consider this overhead to be minimal.  In most real-world applications, the difference in performance will not be noticeable to the end user.

When running the application in release mode with no profiler attached, it took 14.48 seconds to execute the workflow 1,000,000 times.  That works out to 69,039 workflows per second!

I found the performance profiler in VS 2010 to be useful.  While it is much better than no profiler at all, I was a little disappointed.  There are much better profilers on the market today.