Monday, July 19, 2010
« CSLA 4 MVVM video series pre-release off... | Main | CSLA 4 release »

I was just at a family reunion and heard a joke about the comedian’s retirement home. A guy walks into the common room and hears one old guy shout out “19”, and everyone laughs. Across the room another guy shouts out “54” and everyone laughs even harder. The guy turns to his guide and asks “What is going on?”. The guide replies “These guys know all the same jokes, and at their age it takes too long to tell them, so they just assigned them all numbers.” The guy smiles, and shouts out “92”, which results in a just a few grudging chuckles. “What’d I do wrong?” he asks the guide. The guide replies “Some people can tell a joke, some people can’t.”

That made me think about patterns (yes, I know, I’m a geek).

I like design patterns. Who wouldn’t? They are a formalized description of a solution to a specific problem. If you have that problem, then having a formally described solution seems like a dream come true.

Perhaps more importantly patterns are a language short-cut. If everyone in a conversation understands a pattern, the pattern (and often its problem) can be discussed merely by using the pattern name, which saves an immense amount of time as opposed to describing the actual problem and solution in detail.

Of course the “formalized description” is prose. Human language. And therefore it is ambiguous and open to interpretation. The descriptions must be human-readable, because any pattern worth ink and paper transcends any specific platform or programming language. Describing a “pattern” in Java or C# is silly – because that makes it far too likely that it isn’t really a broad pattern, but is simply a practice that happens to work in a given language or on a given platform.

But this ambiguity leads to trouble. Not unlike the comedian’s retirement home, patterns are a short-cut language to some really complex concepts, and often even more complex implementations. While everyone might have a basic comprehension of “inversion of control”, I can guarantee you that saying IoC doesn’t bring the same concept, implementation or emotional response from everyone who hears it.

Pattern zealots often forget (or overlook) the fact that patterns have consequences. Good and bad consequences. Every pattern has bad consequences, as well as good ones. Some people get attached to a pattern because it helped them at some point, and they just assume that pattern will always have a positive or beneficial result. But that’s simply not true. Sometimes the negative consequences of a pattern outweigh the positive – it is all very dependent on the specific problem domain and environment.

Soft things like staffing levels, skill sets, attitudes and time frames all enter into the real world environment. Add the reality that any given problem almost certainly has several patterns that provide solutions – for different variations of the problem – and it becomes clear that no one pattern is always “good”.

It should come as no surprise then, that patterns are often misused – in several different ways.

My pet peeve is when a pattern is applied because something likes the pattern, not because the application actually has the problem the pattern would solve. I often see people using IoC, for example, because it is trendy, not because they actually need the flexibility provided by the pattern. They use a container to create instances of objects that they will never swap out for other implementations. What a waste – they’ve accepted all the negative consequences of the pattern for absolutely no benefit since they don’t have the problem the pattern would solve. Is this the fault of IoC? Of course not, IoC is a powerful pattern.

It is the fault of what I call the “Pattern Of The Year” (POTY) syndrome. When a pattern becomes really popular and trendy, it becomes the POTY. And everyone wants to go to the POTY. If you need the POTY, you should go. But if you don’t need the POTY, it is really a little silly (if not creepy) for you to go to the POTY…

In short: only use a pattern if you have the problem it solves, and the positive consequences outweigh the negative consequences.

Perhaps the most common misuse of patterns is failure to actually understand the pattern or its implementation. To stick with IoC as an example, it is pretty common for a development team to completely misunderstand the pattern or the framework that implements the pattern. Sure, some architect or lead developer “got it” (or so we hope) which is why the team is using the pattern – but you can find apps where numerous competing containers are created, each initialized differently.

I always thought Apple BASIC spaghetti code was the worst thing possible – but misuse of certain design patterns quickly creates a mess that is an order of magnitude worse than anything people wrote back in the early 80’s…

In short: if you use a pattern, make sure your entire team understand the pattern and your implementation of the pattern.

As I mentioned earlier, most problems can be solved by more than one pattern. Any truly interesting problem almost certainly has multiple solutions, each with different good/bad consequences and various subtle differences in outcome. It is not uncommon for the best solution to be a combination of a few more basic patterns.

As an example, the CSLA data portal is a combination of around six basic design patterns that work together in concert to solve the problem space the data portal targets. I’m not saying the data portal is a design pattern, but it is a solution for a problem that came into being by combining several complimentary patterns.

A few years after I created the data portal, various other design patterns were formalized that describe other solutions to this same problem space. Some are similar, some are not. If you look into each solution, it is clear that each one is actually a different combination of some lower level design patterns, working together to solve the problem.

The thing is, every pattern your bring into your solution (or ever pattern brought in by a higher level pattern) comes with its own consequences. You need to be careful to minimize the negative consequences of all those patterns so the overall balance is toward the positive.

In short: don’t be afraid to combine simple or basic design patterns together to solve a bigger problem, but be aware of the negative consequences of every pattern you bring into play.

Having introduced this concept of “low level” vs “high level” patterns, I’m going to follow that a bit further. Most of the patterns in the original GoF book are what I’d call low level patterns. They stand alone and have little or no dependency on each other. Each one solves a very narrow and clear problem and has very clear good/bad consequences.

Of course that was 15 years ago, and since then people have applied the pattern concept to more complex and bigger problem spaces. The resulting solutions (patterns) very often build on other patterns. In other words we’re raising the level of abstraction by building on previous abstractions. And that’s a fine thing.

But it is really important to understand that ultimately patterns are implemented, and the implementations of patterns are often far messier than the abstract though models provided by the patterns themselves. Even that is OK, but there’s a meta-consequence the flows out of this: complexity.

As you start to use higher level patterns, and their implementations, you can easily become locked into not only the implementation of the pattern you wanted, but also the implementations of the lower level patterns on which the implementation is built.

Again I’ll use IoC to illustrate my point. If you want IoC you’ll almost certainly use a pre-existing implementation. And once you pick that framework, you are stuck with it. You won’t want to use more than one IoC framework, because then you’d have multiple containers, each configured differently and each competing for the attention of every developer. The result is a massive increase in complexity, which means a reduction in maintainability and a corresponding increase in cost.

Now suppose you pick some higher level pattern, perhaps a portal or gateway, that is implemented using IoC. If you want the implementation of the gateway pattern you must also accept a dependency on their IoC framework choice.

People often ask me whether (or when will) CSLA .NET will incorporate Enterprise Library, log4net, Unity, Castle/Windsor, <insert your framework here>. I try very, very, very hard to avoid any such dependencies, because as soon as I pick any one of these, I make life really hard for everyone out there who didn’t choose that other framework.

CSLA 3.8 has a dependency on a simple data structure framework, and even that was a continual nightmare. I can hardly express how happy I am that I was able to get rid of that dependency for CSLA 4. Not that the data structure framework was bad – it does a great job – but the complexity introduced by the dependency was just nasty.

In short: be aware of the complexity introduced as high level patterns force you to accept dependencies on lower level patterns and implementations.

The final topic I’d like to cover flows from a conversation I had with Ward Cunningham a few years ago. We were talking about patterns and the “pattern movement”, and how it has become a little warped over time as people actively look for ways to apply patterns, rather than the patterns being used because they are the natural answer to a problem.

It is kind of like a carpenter who spends a lot of money buying some really nice new power tool. And then trying to use that power tool for every part of the construction process – even if that means being less efficient or increasing the complexity of the job – just to use the tool.

Obviously I’d never want to hire such a carpenter to work on my house!!

Yet I’ve seen developers and architects get so fascinated by specific patterns, frameworks or technologies that they do exactly that: increase the complexity of simple problem domains specifically so they can use their new toy concept.

In this conversation Ward suggested that there are different levels of understanding or mastery of patterns. At the most basic level are people just learning what patterns are, followed by people who “get” a pattern and actively seek opportunities to use that pattern. But at higher levels of mastery are people who just do their job and (often without a conscious thought) apply patterns as necessary.

Carpenters don’t think twice about when and how to construct a staircase or put together a 2x6” wall frame. These are common design patterns, but they are natural solutions to common problems.

In short: strive for “pattern mastery” where you are not fixated on the pattern, but instead are just solving problems with natural solutions, such that the pattern “disappears” into the fabric of the overall solution.

The pattern movement has been going on for at least 15 years in our industry. And over that time I think it has been far more beneficial than destructive.

But that doesn’t mean (especially as a consultant) that you don’t walk into many organizations and see horrible misuse of design patterns – the results being higher complexity, lower maintainability and higher cost of development and maintenance.

I think it is important that we continually strive to make patterns be a common abstract language for complex problems and solutions. And I think it is important that we continually educate everyone on development teams about the patterns and implementations we bring into our applications.

But most importantly, I think we need to always make conscious choices, not choices based on trends or fads or because somebody on the team is in love with pattern X or framework Y or technology Z.

  1. Use a pattern because you have the problem it solves
  2. Only use a pattern if the good consequences outweigh the bad (and remember that every pattern has negative consequences)
  3. Use patterns and implementations only if the entire team understands them
  4. Use the simplest pattern that solves your problem
  5. Don’t be afraid to combine several simple patterns to solve a complex problem
  6. Be aware of (and consciously accept) the consequences of any low level patterns that come with most high level pattern implementations
  7. Strive for “pattern mastery”, where you are solving problems with natural solutions, not looking for ways to apply any specific pattern

Eventually maybe we’ll all be in a software development retirement home and we can shout things like “Memento” and “Channel adaptor” and everyone will chuckle with fond memories of how those patterns made our lives easier as we built the software on which the world runs.

Monday, July 19, 2010 11:03:04 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [8]  |  Related posts:
Silverlight 6 doesn’t matter
Why MVVM?
WinRT and .NET
Architect training in May 2011
HTML5 “standard”?
TFS extensibility

Monday, July 19, 2010 5:10:14 PM (Central Standard Time, UTC-06:00)
Agreed.

I can actually see you sitting there as your relative is telling this joke and you're just staring blankly at him/her lost in thought. That might actually be funnier than the joke itself.

But I have been working on a parallel line of reasoning I'd like to just throw out there. I was looking at this research project called Axum a while back and I realized what it was was essentially a language project that tries to incorporate a big design pattern directly into a C#-esque general purpose language. In this case the pattern was trying to solve multi-threading issues using message passing patterns.

And as you know I've been doing a lot of thinking about languages and DSLs and it struck me that, for better or worse, any design pattern could also be expressed as an external (or internal) DSL. As you mentioned one of the downsides with Patterns is added complexity which manifests itself as developers not fully understanding the pattern and therefore only partially implementing the pattern or incorrectly implementing the pattern.

One thing I would like to hypothesize is that, perhaps, a pattern expressed as a DSL would decrease this problem because in an [external] DSL you can't write code outside of the pattern. In effect the DSL becomes a way to actually enforce the use of the Pattern. It can also simplify the actual code written, abstracting away a lot of the cruftiness (if there is any) associated with the underlying languages to coerce it into conforming to the DSL. The concepts will remain complex, there's no getting around that. Learning the pattern and the DSL is still complex... but it makes it harder to get away with not understanding the pattern, which as you called out is also a problem. You can also refactor, in some cases, in a way that will allow you to change a single spot and massive amounts of what would be general purpose code otherwise.

I would also like to hypothesize that constraint increases scalability. Meaning, as your application becomes more and more inherently complex you need to start conforming to design patterns to create constraint, in order to manage that complexity. If you accept the idea that design patterns are needed in order to scale and you accept the idea that [external] DSLs can be used to decrease the negative impact of patterns I feel its safe to conclude that DSLs are needed to scale beyond common levels of complexity we see today.

I would also like to hypothesize that, beyond the ultra simple situations, language abstractions may actually be simpler than logical abstractions. By logical abstraction I mean purely logical design pattern implemented in a general purpose language.

Oh yeah, and 42.
Monday, July 19, 2010 5:23:51 PM (Central Standard Time, UTC-06:00)
Hear Hear!

I couldn't agree more.
Tuesday, July 20, 2010 4:21:50 AM (Central Standard Time, UTC-06:00)
There are at least two more endings to this joke:
1. Someone get's up and punch him in the face. -"We don't tell jokes like this in front of women".
2. Everyone laugh like crazy, and then - "Nice one, we didn't know this one".
robel
Tuesday, July 20, 2010 8:14:19 AM (Central Standard Time, UTC-06:00)
Whilst I respect your arguments, the fact that you presented it in one long blob of text kinda makes it hard to digest.

Now, I'm not saying break it up with some pretty pictures, but an example or two would definitely make it easier to read.
Tuesday, July 20, 2010 8:33:18 AM (Central Standard Time, UTC-06:00)
Very nicely put!
George
Thursday, July 22, 2010 3:14:05 AM (Central Standard Time, UTC-06:00)
Hi

I'm still confused by the whole process of using patterns (and in this instance MVVM)......

We have this article warning of the use/misuse of patterns (and I agree in the main with it's sentiment) but equally we have in the intro video Rocky saying 'if you don't unit test then you don't care, right' and 'if you don't unit test then I suggest you rethink...'

We would all like to improve the efficiency of code maintenance and I agree separation of code from the UI is a good way to achieve this.

'Use a pattern because you have the problem it solves' ....but do I have a problem?... this is the question I'm struggling with.

I don't unit test...is that a problem?

Difficult code to maintain, maybe yes (I have some software [3 clients] and have customised over the years...now it's difficult to maintain and more importantly hindering me in getting new sales/clients as initial setup/customisation is cumbersome - a rewrite is beckoning for this reason and new online requirements)... 1 software app managed by me alone (I have another that's also going to be rewritten [Access 97!!]...is this good enough reason to learn/use MVVM pattern?

I am a newbie to Silverlight so am at a position to start fresh.....MVVM doesn't look easy (some of the concepts I've not used before...the need to use in conjunction with PRISM or other frameworks etc) but am willing to learn.

Is this a misuse of a pattern? I am not a trendy user of patterns but want to set myself up with the best possible chance of building quality, easier maintained software using Silverlight.

Richard



Richard
Thursday, July 22, 2010 10:45:20 AM (Central Standard Time, UTC-06:00)
I am going to add my two cents worth to the discussion. I think an even more important reason to use MVVM in Silverlight is the complete seperation of the graphic design from the business code. I was at a code camp recently and a presenter Michael Washington, showed a simple example where he has pared down also the model-view to a real basic process to be able to demo to people how little you can use to get the job done. Anyway, he showed a small example of a file display kind of like explorer, wasn't really showing much because it was a folder on the server, but interesting. Well when he got the example done, he sent it off to a friend in Britain. He sent back a XAML file for him with a completely different look, with a little bar in the middle with that grew and shrank by how many files were available, and fades and frankly a better use of color. Next he sent it off to another friend who got rid of all the button controls, and everything was a mouse over.....

I looked at him and said you know what you have just discribed is true skinning. You could develop the Amazon of software, buy your complonents, buy your UI and have it anyway you like or hire a designer to make it how ever you would like to see it, frankly a new industry!
Mick
Michael Gamble
Thursday, July 22, 2010 11:24:09 AM (Central Standard Time, UTC-06:00)
I agree Michael. While many people say the primary value of MVVM is testing - I think the primary value (if it is done right) is separation of the view from all code, and the simplicity of implementation that results.

That's counter-intuitive to many people, because a lot of MVVM implementations seem to make things more complex rather than less - but that (imo) is due to flawed implementations of the pattern.

However, I do think testing is important. Very important. Surely Richard, you test your code right? All basic unit testing amounts to is putting your tests into a tool so you can replay them on demand. If that's all you every do - put the tests you already write into a tool for replay - you'll be almost infinitely better off than you are without such an approach.

Unit testing has been built up into this big, scary thing. But it isn't. I honestly can't see why there's ever any resistence to doing it. If a developer doesn't test their code at all they should be fired - that's just incompetent. All I'm saying (and others like Jim Kirkland, creator of nunit), is that at least take that test code and put it into something like mstest or nunit. That's essentially no extra work. And if that's all you do, you instantly gain unit and regression testing.

Of course "no extra work" does imply your code is at least somewhat testable - which code in event handlers is not - and so MVVM comes in handy - because it is testable. Again, at a minimum, it _enables_ the potential of doing even one-off testing, but then if you move those one-off tests into mstest you now have unit and regression tests almost for free.
Comments are closed.