Thursday, July 12, 2012

RESTful MVC with a twist


The MCV layers

Smelly MVC

There are multiple approaches to the MVC design pattern, but few of them ever felt right to me.

One of my main gripes with the pattern described on wikipedia is the dependency cycle between the Controller layer and the View layer. Specifically:

  • A controller can send commands to its associated view.
  • A view must communicate to the controller to activate commands.

Dependency cycles are usually a design smell. While something seems wrong, the answer isn't always obvious.

Another problem arises on the controller layer where the code is usually a mix of commands used to manipulate the model and commands to manipulate the view. I can't help but think that those commands don't belong in the same layer.

The V and C switcharoo

The solution I apply to my designs is to switch the View and Controller layer order, leading to Model Controllers Views or the MCV acronym.

The extra 's' aren't there by mistake, but I'll get to it in a moment.

To make it work, I apply a few extra restrictions.

The Controller layer contains no "View" concepts or commands. It is now responsible to modify the model consistently and also to apply security to any changes being done.

The View layers become a bit more thick. They now contain the required logic to build the visual components and interact with their associated control layer.

A new twist comes from the Controller layers that now generates change events consumed by the View layers. This is necessary for model changes that might trigger controller changes. It also adds the benefit that a developer could modify a control layer while the application is running, and the view would keep reacting appropriately.


A RESTful of shmuck


The constraints imposed by REST usually make most developers queasy. How the hell can we make APIs without context ? How can we accomplish every possible change using only PUT, POST and DELETE?

When it comes to monitoring the controller layer, the context restriction hits straight in the teeth. Most controllers need their context to know which user is executing a command. So how do you offer a REST API to monitor a control layer?

The answer : create a control layer instance for each context.

A sample MCV deployment with multiple instances.
Each user gets their instance of a control layer. Just like every view on a system gets a different view layer instance.

This means a RESTful API can be built to fetch each control layer independently. An administrator or a developer could query the control layer of a specific user to ensure that everything is behaving as expected.

Yo dawg, I heard you like MCV...

...so we put a MCV layer in your MCV layer.

If we have a RESTful API on top of our model, our controllers and our views, what stops us from wrapping all of those things together as a single model? Slap development control layers and development view layers on top of it all and use them to monitor, modify and debug all the layers of a running application?

Besides laziness, nothing makes this impossible.

An application MCV wrapped in a development MCV

I applied this in my pet project : The Deduced Framework. It turned out to be quite convenient; allowing the framework to offer a development environment where everything could be changed while the application is running. Whether it's a view, a controller or a model; everything is laid out in plain view. Developing an entire application without ever stopping it to compile is quite a peasant feeling.

It feels like flirting with the future of development tools, where the idea of stopping an application to compile will be as obsolete as manually managing memory allocation or keeping track of the registries on a CPU.

- Steve McDuff


Friday, July 6, 2012

How should object oriented software work ?

The Lego  Motorized Excavator

Building Blocks

The first time I learned the concept of object oriented, I had an epiphany; I envisioned building software the same way I assembled Lego blocks as a kid. Data and logic blocks would interconnect seamlessly to form applications quickly and efficiently. I would write a piece of code once and I'd be able to reuse it in almost any context. Gone would be the days of duplicated code.

Back to Reality

Reality turned out to be a tad more complex.

C++ allowed multiple inheritance in multiple ways using the optional virtual inheritance. This lead to the creation of new problems and their corresponding solutions.


To simplify things, some languages enforced limitations on how object inheritance would work. Java enforced a single inheritance hierarchy, using interfaces to expose multiple functional aspects.

Data protection concepts emerged to prevent the outside world from modifying internal data. Getters and Setters emerged as best practice to encapsulate data.

Extending existing objects ranges from very easy to impossible depending on whether or not the author of an object anticipated the need to override a specific aspect of his design.

My Ideal World

In an ideal world, I'd like to be able to assemble a class definition by pulling multiple aspects together to form a class definition.

Small data aspects to identify object fields that are common.

Small logic aspects that would pull data together in a reusable fashion.

Experiments

When I started experimenting with the Deduced Framework, one of my goals was to create an easy way to create data structure. Multiple inheritance was a key piece of functionality that allowed users to define those structures and assemble them.

When I added deduction rules and actions to the schema, it soon became apparent that logic could also be encapsulated in small aspects, provided that a few simple rules were followed.


Object inheritance had to occur in a predictable fashion.
For instance, if a type inherited from 3 other types, the order in which each overrides applies had to be well defined.


Object inheritance had to remain simple.
In C++ terms, all inheritance would be virtual. The idea of non-virtual inheritance where you might get more than one instance of a specific field usually adds more confusion than value.


Data and Logic had to be encapsulated in small units
If too many pieces of data or logic are contained in a single type, reusing parts of this type becomes an all or nothing type of deal. You either get all the data and logic or you get none. The idea of separating data from logic in different types also brings values as not all the users of a type will want to reuse the same logic.

Applying those principles became quite handy while defining the data structure used to represent parts of a user interface.

Defining the Data


For instance, when defining the concept of a visual tree, I defined the "Tree Item" type using four data aspects:

  • Named Collection : To apply a name to my tree item.
  • Component Container : To store the visual component used in the tree item.
  • Styled Collection : To apply a visual style to the tree item.
  • Tree Item List Container : To define the list of child tree nodes.

The definition of the "Tree" type reuses 3 of those 4 aspects : "Named Collection", "Styled Collection" and "Tree Item List Container". Only the "Component Container" wasn't applicable.

None of those types contained any logic to maximize reusability.

Defining the Logic


One of my first requirement in defining the logic of my "Tree Item" was to build it based on a configuration. The type "Configured Collection" indicates that aspects of the current object are derived from a configuration. I therefore defined 4 new logic types to configure each data aspect.

  • Configured Name : To apply a name to my tree item based on a configuration.
  • Configured Component Container : To build the component within the tree node based on a configuration.
  • Configured Style : To apply a visual style to the tree item based on a configuration.
  • Configured Tree Item List Container : To create the list of child tree nodes based on a configuration.


Resulting object hierarchy


Benefits

One might argue that a hierarchy composed of 11 different types is complex. However, I believe that complexity in software is usually driven by what we want to accomplish with it. I'd rather accomplish a complex task by aggregating 11 simple concepts together than by creating a few types where the same 11 concepts are regrouped together.

Reusability is also greatly enhanced. When I need to create a new "Tree Item" type where only parts of the fields are driven from a configuration, I can compose a new type by inheriting only the configuration aspects I need.

Best of all, I feel like I'm building software by linking blocks together once again.