Archive

Archive for the ‘SmartClients’ Category

Speaking at alt.NET

September 17th, 2011 Simon Segal No comments

megaphoneI will be speaking at the September meeting of the alt.Net User group about Task Based user interfaces, their benefits and how explicitly modelled code can make the job easier, more manageable and lead to systems that leave the business in control. I will also discuss how this approach can leverage alternative patterns to MVVM and work hand in hand with messaging.

I started a series of posts on this topic recently if you are interested in a preview of the subject matter. You can register here.

Share/Save/Bookmark

Modelling Task based Smart Clients Explicitly–Part 1

August 11th, 2011 Simon Segal No comments

Some time ago when I looked into the MVVM pattern I decided it wasn’t the right choice for me, that hasn’t changed since and I don’t expect it to change anytime soon. The burning question for me was “will MVVM suit my needs”?…and the answer was simply no it wasn’t. I should say however that I do very much like the screen aggregator from the MVVM light libraries and consequently use those quite extensively.

So what were my requirements and how did we1 go about addressing them? I spend a considerable amount of my time building task based user interfaces in smart clients and I prefer to do it very explicitly, but lets break that somewhat fluffy abstract statement down a little with the specifics:

  • Explicitly Task Based means all the way from the XAML layout to the supporting C# code
  • Smart Clients commonly incorporate messaging and the use of durable queues.
  • I want to keep the queries and commands very separate in my code
  • I want a Pipeline for handling UI messages to the controllers (think Ruby or Smalltalk)
  • I’d like an environment where developers stay out of each others way.

Now lets pivot on those one at a time (not all here in part 1 however).

Task Based

Task based user interfaces offer the opportunity to model our screens sharply to the intent of codeadvisorythe user. Consider the example of a grid that allows users to change an employees details, such a grid might include property values such as the first name, last name all the way through to the employees position in the organisation. A ‘position’ of finance clerk might very well be organisationally subject to the concept of banding to determine pay scale.

If we provided this grid based screen for users to change an employees position, the grid cell containing the position might be populated by a combo box containing a list of positions defined by the organisation; a user would simply have to change the selection to affect a position move by an employee. But what is actually going on here in this example?…are we really just changing the employees position, or did something else occur in HR to warrant the position change? Lets say the employee was promoted and lets even assume that HR are interested in why the employee was promote…we can see we have a problem now.

It would strike me as highly surprising if any reader hadn’t been ailed at some point with this syndrome, fumbling around in some legacy relational muck, desperately trying to find ways to reason about data in storage, where the meaning of the events in the system have been inexorably lost.

Explicitly

Being Explicit sounds odd at first blush I know, but consider the example of the employee position changing as discussed previously, certainly its an explicit requirement and event; the promoting of an employee may well require the changing of the position held, its a desirable effect of making the promotion, however there could be exceptions and that indicates even greater need to be explicit. What if I were to be promoted notionally?…let’s say a pay rise with no title bump? But still, how do I do that explicitly, sure it sounds explicit but at a code level what makes it explicit? When it comes right down to it its all about interfaces, in particular what Martin Fowler refers to as ‘role’ interfaces.

Roles

Tasks can be very neatly described in a system by defining a role interface, for example I might name the role in our example as IPromoteAnEmployee.

public interface IActInMakingPromotions: IRole {}

the Commands And Query for the Role

public interface ILoadEmployeePositions : IQuery<IActInMakingPromotions>{}

public interface IPromoteAnEmployee : ICommand<IActInMakingPromotions>{}

Executing this intent explicitly might look something like this:

Controller.Handle<IPromoteAnEmployee>();

OR

Controller.Query<ILoadEmployeePositions>();

At this point the controller knows what it needs to do, or at least a container or some reflection code should be able to locate the applicative handler that will execute the logic for this command.

Note: that there are no data arguments to this command and I haven’t yet said anything about queries, certainly many commands will require facilitating data that is supportive to executing a given command. For example, lets consider that in promoting an employee we may well be expecting access to a list of positions to which any given employee might ascend to (or in the case of demotion descend): enter Command Query Segregation (CQS).

CQRS

Some of the significant benefits of using these roles (interfaces) are that it allows you to vary many of the actors in your system concordantly and we can split the handlers for the commands and queries at a code level by leveraging the CQRS pattern. What about DDD then? Well keeping queries and commands separate is something that jives well with DDD, however I should make it clear that in the case of a smart client where messaging is predominant, many of these commands will most likely re-dispatch their intent from the UI controller to an endpoint where the business logic will be handled and in my case that’s usually an NServiceBus endpoint. In the case of queries we could have our handlers do straight up RPC to the data store or via some http API that acts as a facade to a data store.

Command

public class PromoteAnEmployeeHandler : IPromoteAnEmployee
{
    public void Execute()
    {
        var viewModel = Screen.ViewModel.etc;

        Bus.Send<IPromoteAnEmployee>(m =>
        {
           //…message properties set here using view model if required
        });

        //send a message to other views interested
        Messenger.Default.Send(new EmployeePromotionMade()
        {
            //…inter screen message properties set here
        });
    }

    public IScreen<IPromoteAnEmployee> Screen { get; set; }
    public IBus Bus { get; set; }
}

If this were a typical client server system we could also do straight up RPC with the data store if applicable however in the example above I have dispatched a message on a bus (NServiceBus) to some logical endpoint within the HR service.

Query

public class LoadEmployeePositionsHandler : ILoadEmployeePositions
{
    public void Execute()
    {
        var ctx = new EmployeeViewCache(connectionString);
        var employeePosDescriptions= from p in ctx.PositionDescriptions
                                    select new EmployeePosition()
                                    {
                                        Name = p.PositionName,
                                        Id = p.PositionId
                                    };

        var items = new ObservableCollection<EmployeePosition>();

        Screen.ViewModel.PositionDescriptions = items;
    }

    public IScreen<IPromoteAnEmployee> Screen { get; set; }
}

What’s next?

On the basis that brevity is the essence of wit and not wishing to overly tax the attention span of readers, part 2 & 3 will look at pipelines and how that becomes useful, how SOLID principles are served by such an approach, the multi threaded smart client story and why I am happy to accept lots of small chunks of code spread over many files, little islands of single responsibility as I have come to know them. Finally I will look at afferent and efferent coupling and finish up with testability.

1 Mark Harris and I are co directors of QCAT (an ISV) and Lextrico (a consulting business)

Share/Save/Bookmark

Creative Commons Attribution-ShareAlike 2.5 Australia
Creative Commons Attribution-ShareAlike 2.5 Australia