Ayende @ Rahien

Hi!
My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:

ayende@ayende.com

+972 52-548-6969

, @ Q c

Posts: 18 | Comments: 78

filter by tags archive

EffectusFatten your infrastructure

time to read 4 min | 689 words

Continuing in my exploration of the Effectus code base, which originated from my Building a Desktop To-Do Application with NHibernate article on MSDN Magazine, I wanted to talk today about how to build an application infrastructure.

First, to be clear, I am not talking about infrastructure pieces such as caching, data access, etc. Those are generic concerns and you should be able to just get them from an off the shelve library. When I am talking about an application infrastructure, I am talking about the infrastructure code that you are going to need to write for a particular application. You are always going to have to do that, even if it is something as simple as just wiring the container together, or registering session handling, etc.

From my point of view, the point of the application infrastructure is to make writing the actual application features as simple as possible. Ideally, you want to make the infrastructure pieces handle everything that isn’t purely related to the feature you are implementing. The reason that an application infrastructure can do this while a generic infrastructure cannot is that an application infrastructure can make a lot of assumptions about the way the application is built.

Let us take the Main screen feature in Effectus, shall we, it will let us look at how this is implemented:

public Observable<int> CurrentPage { get; set; }


public
Fact CanMovePrev { get { return new Fact(CurrentPage, () => CurrentPage > 0); } } public Fact CanMoveNext { get { return new Fact(CurrentPage, () => CurrentPage + 1 < NumberOfPages); } } public void OnCreateNew() { Presenters.Show("CreateNew"); } public void OnActionsChoosen(ToDoAction action) { Presenters.Show("Edit", action.Id); } public void OnLoaded() { LoadPage(0); } public void OnMoveNext() { LoadPage(CurrentPage + 1); } public void OnMovePrev() { LoadPage(CurrentPage - 1); }

Looking the code, we can see that there are actually a lot of infrastructure playing a part here.

  • Automatic binding of On[Button Name]() methods to the button command.
    • Within this, enabling / disabling automatically using Can[Button Name] properties
  • Automatic binding of On[List name]Choosen(Item) to the selected item changed behavior on the list.
  • Automatic updates of property states using Fact.
  • Automatic updates of property values, using Observable.

There isn’t much to say about the automatic binding between UI actions and presenter methods, except that I think it is clear how this behavior reduce the level of infrastructure level code that you would have to write, test and maintain. But both Fact and Observable deserve a bit more explanation.

In the LoadPage() method, not shown here, we are updating the CurrentPage property, this will trigger invalidation of the all the facts bound to the value (CanMoveNext, CanMovePrev), which will force their re-evaluation. Since the infrastructure knows how to wire this up to the appropriate commands on the UI, this means that this will enable/disable the given controls automatically. What is more, look at the code. It is clear, concise and pretty easy to reason about and use.

I’ll leave the actual exploration of the implementation to you, it is fairly simple, but the idea is important. The Effectus application actually have more infrastructure code than it have code to implement its features. But that is a very small application. Just to give you an idea, the # of lines of code devoted to infrastructure in Effectus is about 600 LOC! In most applications, you probably wouldn’t even notice the amount of code that the infrastructure takes, but the effects are quite clear.

More posts in "Effectus" series:

  1. (21 Dec 2009) Isolated features
  2. (20 Dec 2009) Fatten your infrastructure
  3. (19 Dec 2009) Building UI based on conventions

Comments

junior programmer

I am looking forward to the rest of the blog posts on Effectus. It deserves a lot more wordings than just the MSDN article. MSDN article seems to be an overview only and a lot of the details didn't have a chance to delve into. It will be extremely good to explore section by section on the reasons behind each design decision and implementation details. Thanks.

junior programmer

I am looking forward to the rest of the blog posts on Effectus. It deserves a lot more wordings than just the MSDN article. The article seems to be an overview only and much of the details didn't have an chance to delve into. It will be much better to explore section by section on the design decisions as well as the implementation details. It will be especially educational for people like me. Nowadays you need to know everything in order to do one thing great. Thanks.

Vadi

Sorry for changing the context of this discussion .. looks like the code may fail when CurrentPage is MaxPage or CurrentPage is 0, I am referring to OnMovePrev and OnMoveNext

firefly

Currently there is no validation logic for the save, which mean if the user enter no data the save will fail. So if I have the pleasure of picking your brain, may I ask where would you put such logic and why?

Nick

Any reason not to pass the observable (or perhaps just the current value) to the fact like this:

return new Fact(CurrentPage, x => x > 0);

Decouples the Fact from the class a little, and should be easier to test the fact in isolation, right?

-Nick

Brendan

I haven't had the chance to look into Effectus but it is on my list of things to do over the holidays.

Typically any windows applications that I develop are client server based and running through a web service, Effectus looks to go straight to the database from what I have read.

Is there any way you could maybe extend Effectus to work over services? It would be a great help to a lot of people and I would be very grateful.

Thanks again for another insight into best practice with NHibernate...

Kevin Gadd

Can't you pull the identity of the Observable directly out of the expression tree, instead of having to specify it twice? That would also allow you to handle expressions that contain multiple Observables.

FallenGameR

Why BackgroundWorker in Effectus.Features.CreateNew calls CompleteSave in thу UI thread? I tested in console App, RunWorkerCompleted runs in a new thread:

private static void Print( string info )

{

Console.WriteLine( "{0}: {1}",

    Thread.CurrentThread.GetHashCode(),

    info );

}

private static void Main( )

{

Print( "Main thread" );


var bw = new BackgroundWorker( );

bw.DoWork += (sender, args) => Print( "Do work thread" );

bw.RunWorkerCompleted += (sender, args) => Print( "Completed thread" );

bw.RunWorkerAsync( );


Thread.Sleep( 500 );

Print( "Press Enter to exit" );

Console.ReadLine( );

}

FallenGameR

Ouch. Forget prev comment. I didn't know it behaves differently in WinForms and WPF apps.

brainboost

Nice concept, first of all. Ok, binding to parameterless events is as easy as elegant but what about 2, 3 and more parameters in events? Are we need to put a method in the Presenters for any parameter case? Played with code, it fits not only WPF but WinForms apps as well, but then you need some presenter modifications.

Ayende Rahien

Vadi,

Why would it fail?

I tested it with both, so I am pretty sure it wouldn't

Ayende Rahien

Firefly,

I would add a validation library, hook it into the DataBindingFactory and have the infrastructure automatically catch ValidationException and show them in the UI in the appropriate manner.

Ayende Rahien

Nick,

The logic that you use isn't necessarily based on the observable, you only need to run it after the observable have run.

Ayende Rahien

Brendan,

A lot of the things in the source code would transfer to a service based model, yes.

Ayende Rahien

Kevin,

I can, but it is:

a) too hard to do for something this trivial.

b) don't assume that the observable is the source of the calculation, it is just the trigger for it.

Ayende Rahien

Brainboost,

I am afraid that I am not sure that I am following you.

If I need N parameters, I am going to have a method with an enumerable parameter

brainboost

Ayende,

Yes, I'm absolutely agree with you about enumerables if you can control event args, but events are different and even one sensible parameter, say on KeyDown event, would require to add handling method, if we need to look at the key pressed. What I have to do is

...

WireEvents(instance);

WireEventsWithParameter(instance);

in Presenters and implement that method in similar manner.

Thank you!

Comment preview

Comments have been closed on this topic.

FUTURE POSTS

  1. Production postmortem: The industry at large - one day from now
  2. The insidious cost of allocations - about one day from now
  3. Buffer allocation strategies: A possible solution - 5 days from now
  4. Buffer allocation strategies: Explaining the solution - 6 days from now
  5. Buffer allocation strategies: Bad usage patterns - 7 days from now

And 2 more posts are pending...

There are posts all the way to Sep 11, 2015

RECENT SERIES

  1. Find the bug (5):
    20 Apr 2011 - Why do I get a Null Reference Exception?
  2. Production postmortem (10):
    01 Sep 2015 - The case of the lying configuration file
  3. What is new in RavenDB 3.5 (7):
    12 Aug 2015 - Monitoring support
  4. Career planning (6):
    24 Jul 2015 - The immortal choices aren't
View all series

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats