Mandy's Tech Blog

View My GitHub Profile

Follow me on Twitter

Come work with me!

Site feed

Bindings and the Model-View-Controller Pattern

There has been a lot of talk lately about the usefulness (or lack thereof) of design patterns in software, but the Model-View-Controller pattern is, without a doubt, one of my favorites. For any who are unfamiliar with it, Model-View-Controller separates the code of an application into three tiers: code that presents an interface to the user (View), code that actually does useful stuff (Model), and code that glues it all together (Controller). On many platforms, such as Apple's Cocoa or Microsoft's WPF, the view may be partially (or completely) implemented without explicitly writing any code, which can greatly speed the development process.

One under-utilized implication of the Model-View-Controller Pattern is that very careful application of the pattern allows models to be reused in multiple contexts; for example, a model might be used as the backbone of both a Windows application and a web application (or theoretically, for a Windows application and a Macintosh application; this is currently rather difficult, although I am working to make it a practical reality). However, even when the models are reused, the views and controllers must be rewritten from scratch. In the case of the view, this is often not a terrible burden, especially when there are good tools for creating views on your platform of choice. On the other hand, rewriting a controller is tedious, boring work. Most of the time, a controller does little more than shuttle data between the view and the model and occasionally disable a control or two. You'd think that there'd be an easier way to hook everything up that didn't involve so much pain and suffering.

As it turns out, you'd be right.

A number of modern MVC frameworks provide a relatively new facility known as "bindings". The UI widgets in such frameworks provide you with the opportunity to specify data sources for various properties (for example, the text in a text field or the enabled state of a button). At runtime, the widgets sign up to receive notifications when the applicable properties on their data sources change (generally using something akin to the Observer pattern). If the data source changes its value for a property, the view will automagically catch this update and change its display accordingly. Likewise, when the user changes a value in the UI, the view propagates this change down to the model.

While this ability to bind directly to a model is incredibly useful and can greatly reduce the amount of code required for many applications, it also leaves us with a question: where do we put all that code that doesn't exactly fit in a model but that also cannot be adequately represented in the view (for example, the enabled state of a button)? One answer that has been proposed is Dan Crevier's DataModel-View-ViewModel pattern. In this pattern, the model (which is renamed to the "data model") and the view remain essentially unchanged, but the controller morphs into being just another model. However, rather than modeling the underlying data, a view model keeps track of application state.

When properly designed, a view model is much more unit testable than a controller, and it seems to me that it ought to be more portable between MVC frameworks, as well. Unfortunately, this pattern comes with a practical hurdle that must be overcome: sometimes, a desired behavior cannot be adequately modeled in a way that is usable by the view. It's often tempting to use this as an excuse to bake platform specific code into a view model, but I find this to be inelegant. In such cases, a developer has two options: either new UI widgets can be created (or extended) to understand the new behaviors, or a controller may be reintroduced in order to serve as a bridge between the view model and the view.

I'm fairly certain that each of these approaches has situations in which it is the best solution, but I strongly suspect that a new controller is the best choice in the majority of cases. While this method does add a fourth tier to the system, which will increase complexity, I believe that in most cases, it will ultimately be less work than baking new functionality right into a view toolkit.

I really wish I could come up with a snappy ending for this post, but it just isn't coming, tonight. In closing, if you're not using MVC in your designs right now (or if you're using it in an undisciplined fashion), I strongly recommend that you study up on it and see if it's right for you. If you're already using MVC, but you aren't using bindings, I'd suggest that you look into whether or not your framework supports them, as they can save you from quite a bit of tedious code.

Technorati Tags: ,

Tutorial for NSDuctTape now available

I've posted an introductory tutorial to NSDuctTape on Google Code.

Expect more in the not-too-distant future.

Technorati Tags: ,,,

Crazy Extension Methods: ToLazyList

Way back in November, I promised to show how to optimize my final version of GetPrimes. Today, I give you the solution to the problem:

using System;
using System.Collections.Generic;
using System.Linq;
 
namespace Utility
{
	public static class EnumerableUtility
	{
		public static IList<T> ToLazyList<T>(this IEnumerable<T> list)
		{
			return new LazyList<T>(list);
		}

		private class LazyList<T> : IList<T>, IDisposable
		{
			public LazyList(IEnumerable<T> list)
			{
				_enumerator = list.GetEnumerator();
				_isFinished = false;
				_cached = new List<T>();
			} 

			public T this[int index]
			{
				get
				{
					if (index < 0)
						throw new ArgumentOutOfRangeException("index"); 
					while (_cached.Count <= index && !_isFinished)
						GetNext();
					return _cached[index];
				}
				set
				{
					throw new NotSupportedException();
				}
			}

			public int Count
			{
				get
				{
					Finish();
					return _cached.Count;
				}
			}

			public IEnumerator<T> GetEnumerator()
			{
				int current = 0;
				while (current < _cached.Count || !_isFinished)
				{
					if (current == _cached.Count)
						GetNext();
					if (current != _cached.Count)
						yield return _cached[current];
					current++;
				}
			}

			public void Dispose()
			{
				_enumerator.Dispose();
				_isFinished = true;
			}

			public int IndexOf(T item)
			{
				int result = _cached.IndexOf(item);
				while (result == -1 && !_isFinished)
				{
					GetNext();
					if (_cached.Last().Equals(item))
						result = _cached.Count - 1;
				}

				return result;
			}

			public void Insert(int index, T item)
			{
				throw new NotSupportedException();
			}

			public void RemoveAt(int index)
			{
				throw new NotSupportedException();
			}

			public void Add(T item)
			{
				throw new NotSupportedException();
			}

			public void Clear()
			{
				throw new NotSupportedException();
			}

			public bool Contains(T item)
			{
				return IndexOf(item) != -1;
			}

			public void CopyTo(T[] array, int arrayIndex)
			{
				foreach (var item in this)
					array[arrayIndex++] = item;
			}

			public bool IsReadOnly
			{
				get { return true; }
			}

			public bool Remove(T item)
			{
				throw new NotSupportedException();
			}

			System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
			{
				return GetEnumerator();
			}

			private void GetNext()
			{
				if (!_isFinished)
				{
					if (_enumerator.MoveNext())
					{
						_cached.Add(_enumerator.Current);
					}
					else
					{
						_isFinished = true;
						_enumerator.Dispose();
					}
				}
			}

			private void Finish()
			{
				while (!_isFinished)
					GetNext();
			} 

			readonly List<T> _cached;
			readonly IEnumerator<T> _enumerator;
			bool _isFinished;
		}
	}
}

Essentially, what the above code does is to wrap an IEnumerable<T> in a layer that disguises it as an IList<T>. Any value that we evaluate is automatically cached for easy lookup later, but we also don't evaluate values until they are specifically demanded.

The implication of this is that you no longer have to choose between caching all of your values up front and evaluating them lazily&emdash;you can have both with relatively little overhead.

Returning to our example of computing primes, if we simply replace this line:

primes = knownPrimes.Concat(computedPrimes)

With this one:

primes = knownPrimes.Concat(computedPrimes).ToLazyList();

Then everything is suddenly fine, and we can compute primes at a very rapid rate.

Technorati Tags: ,,

NSDuctTape on Google Code

This is by no means a huge update, but NSDuctTape is now hosted on Google Code. You can download the source (or binaries) from there, and the code is also hosted on their Subversion servers.

Technorati Tags: ,,,

Announcing NSDuctTape

About a year ago, I started looking for a way to create applications for OS X using the .NET Framework. I found a couple of alternatives, such as Cocoa# and Dumbarton, but neither of them seemed to be quite what I was looking for.

Cocoa# is a project that aims, first and foremost, to create CLR wrappers for most of the classes in the Cocoa library and secondarily, to allow developers to craft classes that are capable of being accessed by Objective C runtime. At first, this sounded like exactly what I wanted--until I realized that Cocoa strongly encourages the use of the Model-View-Controller pattern in its applications, meaning that most of the code written for such an application would be classes that Objective C would be accessing. While the wrappers are cool, the overhead required to create a class that is consumable by the Objective C runtime makes it less than appealing.

Next, I turned to Dumbarton. However, I quickly turned away when I realized that applications using Dumbarton are required to host mono in such a way as to require the application to be released under the GPL [Update: Paolo Molaro, a significant contributor to the Mono project, informs me that this statement is inaccurate. In any case, I would still argue that the issue is confusing enough that many would shy away from using Dumbarton, even if there really is no licensing requirement].  I have nothing against using (or contributing to) GPLed software, but I don't really want to be tied down to it as soon as I begin developing an application.

What was I to do? I looked into contributing to Cocoa#, but its design philosophy is completely different from my own, and I quickly realized that if I wanted to be happy with the result, I would have to write my own library from scratch.

So I did.

I'm posting a very early release of my new library, NSDuctTape, on the website, today. My goal in designing the application was to remove as much friction as possible from the process of designing Model and Controller classes, with the understanding that most views will be defined using Apple's Interface Builder. Today's release supports Models pretty well, and it also supports bindings from Cocoa objects to CLR object properties, so Controllers aren't even always necessary.

I'll post a tutorial soon, but for the moment, you can download it.

Stay tuned for more!

Technorati Tags: ,,,