Spark Skins, Components, and Presentation Models

In the Flex 3.x world, I adopted the Presentation Model pattern and applied it just about everywhere. Separating the non-view logic made perfect sense, far better than the code-behind approach, and cleaned up the view components wonderfully.

Then Spark came along in Flex 4, and things have changed. The framework now has built-in support for separating the "view" (skin) from the "controller" (host component). As I've been using skinning more and more, I've come to wonder if or how the presentation model approach applies in the Spark skin world.

To try and answer that question, I created a fairly simple but non-trivial test application that creates the same views and behavior in three ways. I've heard each of these three ways mentioned at various times by various people, so I used them as the most commonly proposed options:

  • Supply a presentation model to both the skin and the host component, and let it act as a bridge between the two. In other words, the skin knows nothing about the host component, and the host component knows nothing about the skin. Create the PM as a self-contained set of methods and properties that can be applied to any relevant skin or host component. In essence, if the skin is the "view" and the component is the "controller", the PM is the "model" in this mini-MVC configuration.
  • Supply a presentation model to only the host component, and have the host component push state into the skin. In this case, the skin knows nothing about the host component, but the host component it tightly coupled to the skin.
  • Drop the presentation model approach completely. All behavior and properties are held in the host component, and the skin binds to host properties and invokes methods on the host. In this setup, the host knows nothing about the skin, but the skin is tightly coupled to the host.

After building all of these, there are pros and cons to each approach. And some definitely seem to have more pros or more cons than others. The one thing I tend to focus on is what kind of change and what kind of reuse each approach allows for. If you view the running test application, you'll see I've noted some thoughts on each in the sidebar. View source is also enabled, so if you want to look through the code or download it, feel free.

I'm very interested to hear other people's thoughts on this as well. So if you have an opinion on this, or any issues with how I've built any of these versions, by all means please comment below!

Comments Comments (18) | del.ico.us del.icio.us | Digg It! Digg It! | Linking Blogs Linking Blogs | 7597 Views

Taking the "Object Calisthenics" Challenge

In The ThoughtWorks Anthology there is a chapter called "Object Calisthenics". This section lays out a challenge to help push your understanding of object-oriented programming concepts. I decided to take this challenge by building a little Flex application, and I've been quite surprised by its effect. It really does make you think very deeply about what OOP means and how it affects the way you program.

In essence, the challenge is to write a non-trivial (about 1000 lines) program of your choosing that does not violate a set of 9 rules. The rules are very draconian, and they aren't advocating that you actually write all of your software this way (though obeying them in most cases probably would be a good thing). But the goal of the exercise is to really expose any lingering influence of procedural coding and force you to come to terms with them. While I chose to do this in Flex and ActionScript (since that is what I am currently learning in depth), I think some of these would probably need a bit of tweaking in a ColdFusion implementation, but most of it would still apply. Here are the rules:

  1. One level of indentation per method. If you need more than one level in from the start of the method body, create another method and call it. So one level of a loop or if statement is ok, but any deeper and you need to break it out into its own method.
  2. Don't use the ELSE keyword. This one is tough. We're very used to using if/else or switch/case. But good OO designs rely on polymorphism in place of conditional logic.
  3. Wrap all primitives and Strings. That means instead of var zipCode : String, you need var zipCode : ZipCode, and instead of var age : int, you need var age : Age. The idea is to ensure that everything is an object, that the purpose of everything is self-evident from it's type, and that behavior related to that object has somewhere to go.
  4. Use first class collections. This means you can't have var cartItems : ArrayList, but instead have var cartItems : CartItems. This means that behavior related to the collection has a place to live, and that the collection should contain no other instance variables.
  5. One dot per line. This is meant to enforce the Law of Demeter. So this would be a no-no: invoice.lineItems.getLineItem(4). Although this discourages method-chaining in cases where a method returns the same object (a la JQuery), that isn't what this rule is trying to do. It's trying to stop you from reaching across class boundaries and digging into the guts of other objects.
  6. Don't abbreviate anything. This is meant to enforce clarity, as well as identify duplication or misplaced responsibilities. If you're typing mergeUserPreferencesFromDatabaseAndCookies() too often, something is probably wrong, both in terms of what the method is doing and how many things are coupled to it.
  7. Keep entities small. No class over 50 lines, and no package over 10 files.
  8. No classes with more than two instance variables. This is meant to ruthlessly enforce the single responsibility principle for objects. If you need more instance variables, break them into composed objects.
  9. No getter, setter, and property calls to other objects. This mandates the principle to "Tell, don't ask" and enforces strong encapsulation boundaries.

I chose to write a program that generates a game of 10 pin bowling, and then scores it. And wow, writing code to score a game of bowling was actually a lot harder than I initially thought, even without the above rules. But I'm just about done with it and when I am I'll post it here in case anyone wants to take a look at it.

But before I post it, I thought I would ask if anyone else is interested in giving this a shot? Would anyone be up for trying this (with a bowling score card or any other idea you like), sending them to me, and having me post them (anonymously if people prefer) and start a blog discussion about them? I think it would be quite educational to see how different people approach these rules to solve problems, and I'm sure everyone involved would benefit. Any takers?

Comments Comments (14) | del.ico.us del.icio.us | Digg It! Digg It! | Linking Blogs Linking Blogs | 15191 Views

Speaking at cf.Objective() on OO Design and Modeling

I'm a few days late with this, but I just wanted to mention that I'll be speaking at this year's cf.Objective() conference. The topic is "OO Modeling and Design", and if the schedule stays as it is, I'll be giving it at 10:15 am on May 14th.

I'm still thinking about exactly what I want to discuss and how I want to go about it, but here is the general idea that I used for my topic's abstract:

Object-oriented programming is quickly becoming the norm among ColdFusion developers. Unfortunately, OO can be hard to wrap one's head around, and confusion is rampant.

Join Brian Kotek as he explores OO modeling and design. Topics will include:

  • The basics of UML and class diagrams
  • Thinking about the model
  • Design principles
  • Indicators of design quality
  • Theory meets real life

OO is widely understood to deliver the biggest benefit for complex applications that leverage large, behavior-rich domain models. One area that Brian wants to consider is the role of OO techniques applied to "normal" ColdFusion applications. Since many CF apps are "data-centric", what advantages (if any) are gained from adopting OOP for that kind of application? Come to this session to gain a foundation in OO modeling and add your voice to the discussion.

Comments Comments (2) | del.ico.us del.icio.us | Digg It! Digg It! | Linking Blogs Linking Blogs | 6053 Views

Stop Invoking YAGNI Already - It's a Principle, Not a Blindfold

There have recently been a few discussions and blog entries centered around whether getters and setters are good or bad. It seems that invariably someone (or many someones) invoke the YAGNI principle (You Ain't Gonna Need It) as a way to defend their belief that getters and setters are bad, or even useless.

Stop it. YAGNI is a good concept, but I feel that people are trying to use it as a blanket to smother any discussion that involves planning for the future. If YAGNI were applied literally and without thought, we'd all have one giant .cfm file with a huge block of procedural code in it that executed an entire application. Why bother with CFCs at all? Why bother with methods? This can all be done inline in procedural code. A fundamentalist YAGNI view could easily rationalize this decision, and throw solid principles like cohesion, encapsulation, and loose coupling out the window.

Obviously we DO plan for the future when we code. YAGNI is a general principle, not a rigid rule. YAGNI is meant to help avoid over designing something. Do you really need to implement the State Pattern here? Do you really need to create an Abstract Factory and the complexity it brings because you might need to change database platform or encryption algorithms? Almost certainly not. In cases like this, YAGNI can be a valuable litmus test of your design.

However, there are situations where good practice and experience has shown that certain approaches are useful whether you are sure it will change or not. Breaking SQL into it's own classes is almost always a good thing just for the cohesion it offers. One might not be positive that implementing looser coupling is truly needed now, but clearly some attention to basic coupling concerns is always valid. The point is that the idea of balancing concerns has got to be kept in mind. While it can be a grey area, particularly to newcomers to OOP, there is a middle ground between over-engineering and under-engineering. There are situations where something may seem to violate a rigid interpretation of YAGNI that should nonetheless be strongly considered.

Take an example from the Java world of encapsulating object construction. In basic terms, most people create new objects using the "new" keyword, i.e. "foo = new Bar()". The problem with this is that you have given up control of what is being created and how it is being created. Once the "new" keyword is littering your code, any future change to the way something needs to be created is going to be a massive pain to implement.

However, with virtually no extra effort, one can add a huge insurance policy against this situation. By simply making the constructor private and adding a static method called getInstance() that returns a new object, you have moved the logic for how something is created from the calling code (all over your application) into the object itself. Now if you ever need to modify how this object gets created, you have much tighter control over how that happens.

YAGNI would rail against this. But the point is that with 30 seconds of extra work, you have a much more flexible situation. You've potentially saved yourself hours of refactoring and testing in six months. Anyone who would say that that isn't a valid tradeoff is, to me, being very shortsighted.

Again, the point is that many things violate YAGNI in strict principle that are still useful because they are easy, fast, simple, and offer significant potential returns.

Back to getters and setters, I believe these fall into this category. They take virtually no extra effort to create (a snippet or generator will spit out 15 getters and setters at the press of a key). They are not over-engineering your application or blindly pushing large design patterns into your code, which is what YAGNI is really about. It is a simple, easy thing to do that takes very little effort and offers significant potential rewards.

It is true that in an ideal world, we wouldn't even need getters, setters, or public properties. We'd always ask our objects to do things and focus only on the behavior or services an object can provide. Unfortunately, in the real world, data has to get into an object (to populate it) and has to come out of an object (to display it). These boundaries are among the only times invoking getters and setters is justified, but at these boundaries, the encapsulation and clarity that getters and setters provide is, to me, well worth the extra few seconds it takes to generate them.

So, please, feel free to use YAGNI as a guiding principle and let it help keep your code sleek and simple. But don't allow a blind adherence to it to smother potentially good and simple practices that can be very beneficial with very little cost!

Comments Comments (18) | del.ico.us del.icio.us | Digg It! Digg It! | Linking Blogs Linking Blogs | 7572 Views

Ask Brian: Handling Custom Object Behavior

Robb asks:

I have an architecture question. I am building a site with MG2/Transfer/Coldspring and looking to refine my model. I have a User object that can handle several different "user-roles" i.e. admin, prospect, agent, etc... I have been struggling with the best way to provide the configuration details/properties for each user-role. I don't want to end up with class explosion with say a strategy pattern or even a quasi-abstract CF factory method. I am not sure that configuration details/properties should be a singleton CS managed object as they are more transient but what is the best way to handle?

Robb is looking for a way to assign custom behavior to his User object. To his credit, he isn't immediately trying to go down the inheritance path, which is what many people will initially try. The idea of creating a base User object and extending it with AdminUser, AgentUser, etc. looks easy and appropriate upon first glance. Unfortunately, it has a big problem: inheritance is static and it is a "one or the other" proposition.

In other words, what if you have an Agent who is also an Admin? This gets nasty very quickly. What do you do, go with User > Agent > AdminAgent? Or User > Admin > AgentAdmin? This is the very definition of a class explosion, and again, it is good that Robb appears to see the problems with trying that approach.

Robb mentioned the Strategy Pattern, which might be a good fit. His fear of a class explosion here may be misplaced though. Clearly, the Strategy pattern will cause much less of a class explosion than inheritance probably would. And the bottom line is that the custom behavior has to live somewhere. So my take would be something like this:

There's really nothing wrong with this, and there really is no class explosion. You have one class for each type of specialized behavior you which to apply to a User. It doesn't get much tighter than that. He can also associate more than one Strategy with a User if necessary. The only downside here is that the User object needs to have a static API (unless you want to start playing with method injection but that is another topic and would add another layer of complexity). In other words, the User object would need a method for doAgentThing() even if that particular User instance did not use the Agent role strategy. This may not be an issue, and in fact it may be a good thing for the object to always have a known API.

There is another take on the problem, which essentially reverse the composition relationship. This is the Decorator Pattern. It might look like this:

You can see that it is almost identical to the Strategy Pattern except that the relationship is reversed. Essentailly, the Decorator "wraps around" the original object and adds additional behavior. Again we have one class per custom set of behavior we want to apply. And a User can have more than one Decorator applied (sort of a "russian dolls" approach where we have more than one wrapper). But the difference here is that the API of the Decorator would not remain static. The object would have a doAgentThing() method only if the Agent decorator was applied to the User.

This might be a benefit or a drawback depending on how you create and use the object and how certain you are of what kind of object you are dealing with. But it does introduce coupling, because now the code using the object needs to know what kind of User it is dealing with. This is called "type coupling" because the calling code has to know which type of User it is interacting with. In some cases this might be fine. i.e. if you know you are only calling agent-related methods from within some other agent-specific code, this may not be a problem. (One could also specify all possible Decorator methods in the abstract UserDecorator class and have it throw an error or do nothing if the User doesn't have a specific decorator applied, but then we get into needing to handle exceptions in the calling code which would also add more complexity.)

As you can see, there are a few ways one might address this problem and they each have their own benefits and consequences. Which one Robb might use probably depends on how he uses the User, how important it is that the User object maintain a stable API, and how much type coupling he is willing to accept when using the object from other code.

Hopefully that gives Robb some ideas to consider. If anyone has comments or other ideas, please feel free to comment and give your thoughts. Thanks!

Comments Comments (2) | del.ico.us del.icio.us | Digg It! Digg It! | Linking Blogs Linking Blogs | 8035 Views

More Entries