I just have time for a really small post today because I spent the time after class hanging out pool side talking about indexing strategies, frameworks, high resolutions drum scans, ColdFusion 9, scalability, how to open beer bottles with just about anything you can find on your key chain, and host of other fun topics. Then, after that, Charlie Griefer and I spent some time discussing "what it means to be deck of playing cards." All in all, it was a great evening with some great people.
But, the day concerned more than just how many things Steve has deep fried is his kitchen (and frankly, after he mentioned a deep fried McRib sandwich, I am not sure I could have taken much more). For me, there was one really great break through for the day. The break through itself is so obvious once you step back and think about it; but, until you do, not thinking about it can add a lot of mental stress and confusion.
The break through was in regard to the Open-Close principle. This principle states that an object should be open to extension, closed to modification. The idea here is that if you find yourself having to open up code every time you want to add new functionality, then the things you are changing should probably be factored out and encapsulated somehow. All to say, the code should be closed to direct modification, but open to extensions in functionality through other means (such as sub-classing and strategies).
The Open-Close principle is definitely one that feels right and makes a lot of sense. But, if you don't fully know where to apply it, then you can start to doubt your architecture every time you need to make updates. My breakthrough was when Hal stated that the Open-Close principle applied only to the Domain Model and that is has nothing to do with the UI (user interface) or the Controller layers.
Now, if you stop and think about that comment, obviously it has to be true; I mean, if you add functionality to an application, then it necessitates that you update your UI and your Controller layer to accommodate that new functionality. But the breakthrough that was afforded by the explicit recognition that changing the Controller layer was OK is that it was also OK to update logic that surrounds sub-class selection. By that, I mean that at some point, somewhere, some logic is going to need to decide which sub-class to instantiate for a given reason. And, if creating new sub-classes is a way for us to extend code rather than modify it, we'll still need to modify some code to handle the new sub-class selection. All to say that while the Open-Close principle is excellent, modification to code does need to take place and is not necessarily an indicator that your architecture is flawed.
| || || || || |
| || |
| || || |
| || || || || |
| || |
| || || |
Looking For A New Job?
Ooops, there are no jobs. Post one now for only $29 and own this real estate!
Interesting. So how do you reconcile that with duck typing?
Blarg. This is why you don't comment at 1am.
When I said "duck typing", I meant to say "method injection". I have no idea why it came out the other way.
Hi Ben, sounds like you, Hal and Clark are having a great time so far!
First, just to be pedantic, it's the "Open-Closed" principle. ;-)
In terms of obeying this principle, I think that, like all OO principles, it's a guideline. It's not like the OO police will come shoot you if you modify a class heh. But the idea is to minimize it as much as possible, as well as ensuring that any single change that IS needed is localized to ONE place.
This is where something like factories can be very helpful, as I'm sure you know. That way, if you add a new class, the change should be limited to the factory since it is the only class that should have type coupling to the classes being created. And if you can go even further and extract this knowledge into metadata, you can actually make changes like this without touching the actual code at all, just by changing an configuration file or IoC container. As always, it depends hehe.
Keep posting, I am enjoying reading about how this is going! Thanks.
I am not sure that method injection is necessarily any different than something like sub-classing. Obviously they are very different in their expression, but in a way, they are both techniques that can be used to extend a class in somewhat dynamic ways. That said, whether you are injecting something or sub-classing something, the calling code still needs to be able to choose what action to take. That is, either a sub-class or an injected entity needs to be selected; so, as those set of sub-classes and the set of injected identities grows, the Switching or IF statements or whatever needs to be updated in the calling code.
Absolutely, I agree with you. I think one of the pitfalls that new OOP disciples fall into is that each rule is golden and when you break it, there's a problem (I know I have falling into that many times). The beauty of what Hal said was not so much that it was very insightful (not to demean it in any way) - the beauty was that is was a slap in the face with reality :)
I definitely like the idea of a Factory handling logic like this. Also, if you don't have any IoC framework, I would be comfortable with the Controller making these kinds of decisions so long as you don't start to repeat the logic in multiple places.
I was just thinking about the Open-Closed principle as I contemplated making some edits to an object. I think the question for me would be when is an object done and considered to be "closed". Be it right or wrong, some web apps are never considered finished and are notorious for having new functionality added after deploying. When a new feature comes up, it would have to be a balance between keeping the original object closed to modification and not creating too many extensions (i.e., maintenance headaches).
I'm still trying to get this stuff. Obviously, if things need to be changed, they need to be changed; but, I suppose the point is that you want to architect extensibility in as much as possible so that when you need to make changes, the number of places you need to change can be minimized.