Tuesday, June 17, 2008

Design patterns as religion

I've come to an understanding of and guarded appreciation for design patterns.

They're not at all useful in and of themselves, but they are useful at a level of abstraction - they give us a common language to explain our implementations with ("...so basically, the model objects are just kind of structs and we cajole them into doing interesting things by Decorating them...") and, more importantly, they let us learn about the boundaries, limitations and realities of the design space that we're working in by revealing the problems that get solved and solved again and again and... you get the picture.

If your objects start to look like a pattern, it's a curiosity. Patterns were discovered "in the wild" to begin with, so don't tire your arm out patting yourself on the back for rediscovering one. No gold star for knocking out a Flyweight, sorry. On the flip side, don't flagellate yourself when you realize that you've implemented a Singleton - if it emerges from solid design, why would you throw it away?

It doesn't matter if you're blindly implementing a pattern or blindly rejecting an implementation because it looks like a pattern that someone on the Internets doesn't like - it's cargo cult programming either way.

Design patterns are there and were there before anyone started looking for them or writing about them. People have classified subroutines as a design pattern - like other "patterns", this isn't a reason to use or not use them, it's further establishing where they come from - introspection on how we make programs work. There's something to be said for taking a stroll through that meta-field, but I don't linger there too long. Most of the time.

All this is a long-winded way of explaining why my monocole absolutely popped out the other day at work. I was busy doing something or other at the time (transliterating objects to an XML format I don't control using unhealthy amounts of Reflection, I think?) when I saw one of the other developers explaining something or other. I popped out my earphones to catch the explanation midway through.

He had the Head First Design Patterns book open on his desk and was walking through his ideas.

"Why are we bothering with inheritance? The domain model you guys put together is too convoluted and doesn't work in this case."

"If there's something we missed, it's not like it's set in stone. If it's really hairy, we can walk through it and see if there's some reasonable way to get it factored in and if there isn't, we can go further back and see how we can make the model work for us."

"The <I forgot already!> pattern says that you can use hashtables to store the data for your objects, rather than inheriting from a base class."

"Well, yeah. But think about why we use objects and I think you'll see why that's probably a bad idea."

...

"For our model objects, we're use them not only to encapsulate associated data but to make it easily discoverable - when you're working with them internally, it may seem pretty convoluted that your parent base Foo class has property Bar that's exposed by a child Buz object (which has more properties and methods from the IBaz interface that Foo implements), but that's all readily discoverable by anyone who's consuming a Buz object. They could kind of care less how it works, they just need access to have access to its state and be able to send it messages to have it do interesting things."

He was not sold by my explanation and the discussion closed in on arguing (something about our respective tones and the other developers in the office getting quiet and looking uncomfortable) about whether it makes more sense to have the classes representing data internally like a struct or as a hashtable - I scoffed (and still scoff!) at the idea but told him that he was the one implementing it, so if he had a good reason for properties exposing a hashtable behind the scenes, I was fine with it.

I started to look up hashtables and figure out whether he was really on to something or whether my gut feeling that it was adding an unnecessary level of complexity to the design (OK, I was premature optimizing in my head and wondering about the relative weight of sparsely-populated hashtables, too) when, a few minutes and pages in the book later, he announced to another developer in the office (!!!) that the book said that you should only use hashtables when you're dealing with a lot of inheritance and a lot of properties.

I don't think there was any amount of selling I could have done to get him to walk away from the curious implementation - it was design pattern as dogma. Blinders on, reject facts, implement on faith and The Pattern will see you through.

I'm still trying to figure out if I was wrong (probably, yeah) for knee-jerking away the use of hashtables or not. I'll let you know when I turn that page.

No comments: