Jeremy D. Miller -- The Shade Tree Developer

Sponsors

The Lounge

Wicked Cool Jobs

Syndication

News

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
Build your own CAB #13 - Embedded Controllers with a Dash of DSL

Start with http://andersnoras.com/blogs/anoras/archive/2007/07/04/i-m-coming-down-with-a-serious-case-of-the-dsls.aspx and come back.

Just to continue the world's longest run on sentence.  Before I start, here's the table of contents for the "Build your own CAB" series:

  1. Preamble
  2. The Humble Dialog Box
  3. Supervising Controller
  4. Passive View
  5. Presentation Model
  6. View to Presenter Communication
  7. Answering some questions
  8. What's the Model?
  9. Assigning Responsibilities in a Model View Presenter Architecture
  10. Domain Centric Validation with the Notification Pattern
  11. Unit Testing the UI with NUnitForms
  12. Event Aggregator
  13. Rein in runaway events with the "Latch"
  14. Embedded Controllers with a Dash of DSL (This Post)
  15. MicroControllers - Forthcoming
  16. Subcutaneous Testing - Forthcoming
  17. Creating the Application Shell - probably a couple posts
  18. Wiring the Components with an IoC tool - Forthcoming

Why is this post necessary?

Why, you might ask, are you writing a post on what amounts to a "ViewHelper?"  One simple reason - View's can easily become absolutely massive blobs of code.  Any chance to move a cohesive set of screen responsibilities into another class should serve to make the View itself simpler, and that's all this post is about.  Plus, breaking a View's behavior into multiple, cohesive classes can potentially lead to reuse opportunities for the little Embedded Controller classes.

For much of the last three years I've worked with a lot of legacy code over a half-dozen different codebase's.  All of them, to be charitable, were less than ideal in quality and structure.  If you ask me what the single biggest flaw or problem across all of these codebase's my answer would be near automatic -- long classes and long methods.  What I continuously see is code stuffed into modules until the modules are coming apart at the seams. 

Come to think of it, my current project is about 95% greenfield code so far.  Come Thanksgiving time when it's my turn to say what I'm thankful for my answer might just be "I'm thankful for getting six months of working on a greenfield project."

Embedded Controller

Again, I'm not a sanctioned patterns naming body, but the term "Embedded Controller" is my name for nonvisual classes that help a View control some distinct part of it's behavior.  The first example that comes to my mind is from a WinForms project that used a 3rd party grid (not a vendor on the CodeBetter friends list by the way).  The grid control needed a lot of consistent help and infrastructure code around it to implement the behavior we needed (little things like sorting and paging).  We quickly discovered that additional screens needed the exact same bootstrapping code, so the obvious answer was to extract that "grid helper" into it's own reusable class.  We were using a pretty strict Passive View approach, but even so, we didn't want the Presenter's tied that tightly to the screen mechanics.  Instead, the new GridHelper class was just something that the View controls used internally.  After the third screen with the grid control, development suddenly went faster. 

To differentiate Embedded Controller classes somewhat from the Presenter, here's the attributes of an Embedded Controller:

  • Nonvisual class used by a View to implement some of the View behavior.  I guess in
  • Completely encapsulated within a View.  There is no sign of the Embedded Controller in a View's publicly facing interface.
  • Embedded Controller's are happily aware of the actual, concrete UI widgets.  The Embedded Controller class "knows" about buttons and checkbox's and the nasty 3rd party grid that you're being forced to use.
  • Very limited in scope.  An Embedded Controller provides classical controller functionality for a very specific part of the screen

 

My advice for taking advantage of Embedded Controller's is threefold:

  1. Look for common UI coding tasks within a system and look for opportunities to encapsulate some screen mechanics in reusable pieces.  This is just another exercise in eliminating duplication.
  2. Split up any View class that gets too big.  I might have left the impression in earlier posts that the View code is somehow exempt from the normal coding standards because we've made it "simpler" now.  Code quality matters everywhere, and especially in areas of the code that are likely to change over time -- like View's.  Even with a Passive View architecture a complex screen will almost inevitably lead to complex code in the View.
  3. Pulling out an Embedded Controller might be an easy way to extend unit testing deeper into the View.  This won't always be true, but a "POCO" embedded controller class can often be quite easy to unit test inside vanilla xUnit tests without resorting to anything exotic like NUnitForms.  There is some widget behavior that only functions when a Form is visibly displayed, but a lot of behavior can be tested just by instantiating UI widgets directly within a unit test.  One way or another the UI widget stuff is nothing but CLR classes.

 

Sample:  The Control State Machine

Here's a scenario from my current project that I bet all of us have dealt with a few times over.  We have a Trade screen that has seven different states depending upon whether you're creating or reviewing a Trade.  The various user actions available on the screen differ from state to state.  As the screen changes state either upon opening the screen or a result of user actions while it's open we need to enable/disable and show/hide different screen elements.  The screen started simple, so I just coded specific methods at first to enable or disable bits of the screen.  Fast forward a couple of weeks and the behavioral logic had exploded (funny how that happens when you actually get to talk to the end users).  Unsurprisingly, the code in the Presenter and View had become hairy, plus the screen had way too much flicker for that matter. 

Before I show any code, let's be pretty clear that this code is not very optimized or even very powerful.  All I want to talk about is the concepts and structure of the design irrespective of performance.

At least in concept, the solution was pretty simple.  Move that logic into a state machine construct.  Since we already had a full set of regression tests against the UI screen itself, I felt pretty safe making the changes.  All I did was create a class called "ControlState" that's nothing but a collection of Control's to display and enable for a particular screen state.  ControlState has a method called Activate() which simply loops through its internal collection to enable and show the configured controls (it's not shown but the call to Activate() is wrapped in SuspendLayout() and ResumeLayout()). 

 

        public class ControlState
        {
            private List<Control> _displayedItems = new List<Control>();
            private List<Control> _enabledItems = new List<Control>();
 
            public void ShowControls(params Control[] controls)
            {
                _displayedItems.AddRange(controls);
            }
 
            public void EnableControls(params Control[] controls)
            {
                _enabledItems.AddRange(controls);
            }
 
            public void Activate(ControlStateMachine<T> machine)
            {
                machine.LevelSet();
 
                foreach (Control item in _enabledItems)
                {
                    item.Enabled = true;
                }
 
                foreach (Control item in _displayedItems)
                {
                    item.Visible = true;
                }
            }
        }

As you can probably guess, there's a second class that aggregates all of the configured ControlState's and Control's called ControlStateMachine<T>, where T is an enumeration of the possible states.  Here's a little bit of its implementation. 

 

        private readonly Control _parent;
        private readonly IScreenBinder _binder;
        private List<Control> _displayedItems = new List<Control>();
        private List<Control> _enabledItems = new List<Control>();
        private Dictionary<T, ControlState> _states = new Dictionary<T, ControlState>();
        private T _currentState;
 
        public ControlStateMachine(Control parent, IScreenBinder binder)
        {
            _parent = parent;
            _binder = binder;
        }
 
        public void SetState(T stateKey)
        {
            _parent.SuspendLayout();
 
            _states[stateKey].Activate(_binder, this);
            _currentState = stateKey;
 
            _parent.ResumeLayout();
        }

The View itself just calls ControlStateMachine.SetState() to configure itself.

Now, for the cool part.  Here's a somewhat obfuscated version of our code that defines the state machine inside the View.* 

        private void configureStateMachine()
        {
            _stateMachine = new ControlStateMachine<TradeDetailState>(this, _binder);
 
            _stateMachine.OnStateChangeTo(TradeDetailState.Creation)
                .Show(createTradeButtonsPanel)
                .Enable(status1CheckBox, status2CheckBox, status3CheckBox, externalTradeIdTextbox);
 
            _stateMachine.OnStateChangeTo(TradeDetailState.Review)
                .Show(updateTradeButtonsPanel)
                .IsReadOnly()
                .Enable(
                    editTradeButton, 
                    status1CheckBox, 
                    status2CheckBox, 
                    status3CheckBox, 
                    externalTradeIdTextbox, 
                    cancelTradeButton);
 
            _stateMachine.OnStateChangeTo(TradeDetailState.ReviewDirty)
                .Show(updateTradeButtonsPanel)
                .IsReadOnly()
                .Enable(
                    undoButton, 
                    status1CheckBox, 
                    status2CheckBox, 
                    status3CheckBox, 
                    submitTradeChangesButton, 
                    externalTradeIdTextbox, 
                    cancelTradeButton);
 
            _stateMachine.OnStateChangeTo(TradeDetailState.Edit)
                .Show(updateTradeButtonsPanel)
                .Enable(externalTradeIdTextbox, cancelTradeButton);
 
            _stateMachine.OnStateChangeTo(TradeDetailState.EditDirty)
                .Show(updateTradeButtonsPanel)
                .Enable(undoButton, submitTradeChangesButton, externalTradeIdTextbox, cancelTradeButton);
 
            _stateMachine.OnStateChangeTo(TradeDetailState.Cancelled)
                .Show(updateTradeButtonsPanel)
                .DisableEverything()
                .IsReadOnly();
 
            _stateMachine.OnStateChangeTo(TradeDetailState.History)
                .Show()
                .DisableEverything()
                .IsReadOnly();
        }

If you haven't seen this kind of syntax before, it's what Martin Fowler (a real patterns naming authority) has christened Fluent Interface.  Why, oh why, did I go to the extra trouble of making a Fluent Interface instead of just defining the state machine by filling up the collection state (and let's be clear, it is a little more work)?  Because I thought it would make a good blog post wanted to create Domain Specific Language in the code to make the code easier to understand.

 

That's Not Really a DSL!

Unfortunately, in my opinion, the .Net community is fixated on graphical Domain Specific Language's (DSL) that revolve around yet more code generating visual tooling.  There's a complete other side to the DSL's however.  Another alternative is lexical languages which could be either internal/embedded or external to the language, with the pro-lexical argument being something like "people can read English you know."  I'm not particularly enamoured of creating my own programming language and interpreter, so my particular area of interest right now is in creating embedded DSL-like syntax's inside existing languages.  Granted, C# is very limited in this respect compared to other languages, but we can still achieve some useful gains with Fluent Interface coding. 

We're about to get IronRuby and C# 3 as fullblown CLR languages.  Both languages, and especially IronRuby, are far better suited for internal DSL's than C# 2.0.  The Ruby hype seems to be 9/10's Rails, but the stuff that ThoughtWorks and others are doing with expressive DSL development in Ruby might turn out to be the real value proposition behind Ruby.

So is my little ControlStateMachine a DSL or just an API?  Running it through the Is It a DSL or an API Checklist, the answer is probably no, but the real value is simply an expressive AP.  The real goal (or enabler) is to move toward coding syntax's and API's that speak clearly in the semantics of the problem domain.  The general idea is that the correctness, or intent, of the code should become much more readily verified through simple inspection.  Ideally, you could move to the point where you are able to show your business logic code to the actual business users.  There will still be plenty going on behind the scenes, but they don't need to see that.

 

David A. Black has a good post on Domain Specific Language that I'd recommend for a jumping off point.

I haven't delved deeply enough yet, but Boo sounds like a good way to create lexical DSL's in .Net today.

 

* It's obviously a screen for capturing a Trade, but since half of the developers in New York seem to be working on a similar project at any given time, I'm not too concerned about publishing this.


Posted Fri, Jul 6 2007 12:40 PM by Jeremy D. Miller

[Advertisement]

Comments

Brendan Tompkins wrote re: Build your own CAB #13 - Embedded Controllers with a Dash of DSL
on Fri, Jul 6 2007 5:19 PM

Jeremy, I think you've written a short book on this topic.  It's great!  

Sam Gentile wrote New and Notable 177
on Wed, Jul 11 2007 8:16 AM

Multithreading and Concurrency Software Transactional Memory Part IV - Thread-Bound Transactions Software

on Fri, Jul 13 2007 5:28 AM

Aside: I guess this post is really about mock frameworks rather than mocks, but I didn't want to break

Noticias externas wrote The mess that mocks can make
on Fri, Jul 13 2007 6:02 AM

Aside: I guess this post is really about mock frameworks rather than mocks, but I didn&#39;t want to

Jeremy D. Miller -- The Shade Tree Developer wrote Build your own CAB #14: Managing Menu State with MicroController's, Command's, a Layer SuperType, some StructureMap Pixie Dust, and a Dollop of Fluent Interface
on Tue, Jul 24 2007 5:18 AM

The title is a mouthful and accurately implies an alarmingly high jargon to code ration, but I just didn&#39;t

Jeremy D. Miller -- The Shade Tree Developer wrote The Build Your Own CAB Series Table of Contents
on Wed, Jul 25 2007 9:22 PM

Yes, this is overdue. Here is an introduction and table of contents to my &quot;Build Your Own CAB&quot;

Jeremy D. Miller -- The Shade Tree Developer wrote Build your own CAB #14: Managing Menu State with MicroController's, Command's, a Layer SuperType, some StructureMap Pixie Dust, and a Dollop of Fluent Interface
on Thu, Jul 26 2007 10:57 AM

The title is a mouthful and accurately implies an alarmingly high jargon to code ration, but I just didn&#39;t

Jeremy D. Miller -- The Shade Tree Developer wrote Resources from my DevTeach talks
on Thu, Nov 29 2007 12:04 PM

To everybody that attended one of my talks at DevTeach this week. All of the materials are now online

hairy plus wrote hairy plus
on Thu, Apr 10 2008 1:37 PM

Pingback from  hairy plus

Estado de las vistas (y II) « Carli??os Blog wrote Estado de las vistas (y II) &laquo; Carli??os Blog
on Sat, Jul 26 2008 10:48 AM

Pingback from  Estado de las vistas (y II) &laquo; Carli??os Blog

Alex wrote re: Build your own CAB #13 - Embedded Controllers with a Dash of DSL
on Wed, Oct 22 2008 7:49 AM

Complicated dialogs (containing hundreds of controls) usually have LOTS of code related to intercontrol dependency. E.g. on some CheckBox's Checked event we want to do lots of things - not only enable/disable/hide/show other controls but also change their values, refill combos/grids/lists, etc. And when enabling/disabling/hiding/showing - we want to take into consideration complex logical conditions containing not only some properties of some controls but "external" data as well (e.g. permissions of current users, some app.settings etc). So I wonder if your configureStateMachine() approach is capable of handling such complex scenarios? I can't even imagine how can I separate all this mess into separate "states". Can you give a piece of code demonstrating some complex processing? Thank you.

Sam Gentile's Blog wrote New and Notable 177
on Tue, Dec 2 2008 8:38 PM

Multithreading and Concurrency Software Transactional Memory Part IV - Thread-Bound Transactions Software Transactional Memory Part V - Integration with System.Transactions Parallel LINQ Restating the Concurrency Problem Herb Sutter is starting a new

Creating simple state machine using C# 2.0 iterators « Big Ball of Mud wrote Creating simple state machine using C# 2.0 iterators &laquo; Big Ball of Mud
on Fri, Mar 20 2009 8:29 PM

Pingback from  Creating simple state machine using C# 2.0 iterators &laquo; Big Ball of Mud

Creating simple state machines using C# 2.0 iterators « Big Ball of Mud wrote Creating simple state machines using C# 2.0 iterators &laquo; Big Ball of Mud
on Fri, Mar 20 2009 8:30 PM

Pingback from  Creating simple state machines using C# 2.0 iterators &laquo; Big Ball of Mud

Add a Comment

(required)  
(optional)
(required)  
Remember Me?
Devlicio.us