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 | 2138 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 | 1429 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 | 2237 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 | 3048 Views

Ask Brian: How to Handle Object Composition?

Christopher R contacted me through my contact form to ask about object composition. I thought I would answer it here in case it helps other folks as well. I'm also planning on answering questions like this going forward, so if anyone has questions that you think I can help with, feel free to contact me through the blog and I'll do my best to answer!

greetings...i recently came across a great article you wrote called "Write efficient code with the Composition object pattern and CFCs". it greatly assisted in my initial dilemma involving how to relate distinct but related classes. the current article works for related classes (PhoneNumber) into which you pass a final piece of data (e.g. the phone number). however, whats the best approach when that data is merely a reference or pointer (e.g. PhoneID) that requires further querying / creation of data access objects? as an example, several customers may share the same phone number (PhoneID). in this case - bear in mind that we still want to stick to OOP + not introduce db queries into the related class (e.g. PhoneID.cfc) - we might use a DAO to communicate with the related class (e.g. PhoneDAO.cfc) into which we would need to pass a database ref along with the PhoneID(s) in order to find the proper record. i would like to return a reference to the Phone object that the main class (e.g.Customer) could then utilize. to better elucidate the approach, im following a series of articles at iknowkingfoo.

hopefully this makes some sense - difficult to encapsulate in writing succintly. im getting up in arms as far as these objects, accessing their data as well as trying to access application variables. any help greatly appreciated.

thanks in advance.

To reiterate, composition models a "has-a" relationship between objects, as opposed to an "is-a" relationship which is typically done through inheritance or interface implementation. However, Christopher seems to be working with two different kinds of objects here: Singletons and business objects. How you handle the composition can depend on the kind of object you are dealing with and what they are meant to do.

For example, a PhoneDAO would almost certainly be a Singleton object, meaning that only one instance of the PhoneDAO exists in the application. However, a PhoneNumber object would be a business object, meaning that there could be many instances of PhoneNumber, each with their own data, modeling many different actual phone numbers. The same goes for Customer. Customer is a business object.

The question seems to be how to build up composite object relationships in your business objects. The answer is usually to use a Factory to build your business object. The Factory would also be a Singleton since you only need one. So Christopher might consider creating a CustomerFactory which he would call "getCustomer(13)" on to create an instance of that Customer and return it. The factory would then be responsible for also creating and setting any composite objects. As a result, the factory may itself have other singletons composed within it such as a CustomerDAO, PhoneNumberDAO, etc. The factory would use these objects and know what to do with the results (in this case, setting the resulting PhoneNumber into the resulting Customer before returning it).

The idea with factories is not only that they create objects. It has to do with the primary OO design principle of encapsulation. What the factory encapsulates is knowledge of how to create and relate a Customer and a PhoneNumber. This is crucial to understand, because it means that you become free to change how the Customer and PhoneNumber are created and related at any time. Nothing outside the factory would ever know that you made any changes.

Consider the Transfer ORM framework. Transfer handles making queries to the database as well as building object relationships for you. It is very handy, and I would recommend that Christopher have a look at it when he has the time to evaluate it. But lets say that he creates a CustomerFactory and any code that needs a user calls customerFactory.createCustomer(id). If he later decides to use Transfer, he can easily make that change because he only has to change one thing: the CustomerFactory. He can remove his own DAOs and rip out the logic that relates these objects, and replace it with calls to Transfer. Nothing outside his factory needs to know that the way these objects are being created has changed. That is the beauty and power of encapsulation, and why factories are so useful.

For building composite relationships in your Singletons, there is another option to consider: the ColdSpring framework. This framework is designed primarily to "wire up" or relate your Singleton objects. That means things like Services, DAOs, Gateways, etc. It is a really powerful tool but does have a learning curve to wrap your head around. I have a number of blog entries on ColdSpring and there are numerous other blogs and mailing lists that can help with this as well. If you give ColdSpring a look and I can offer any additional help please let me know.

Hopefully that helps, Christopher? I'd look at using a factory to handle creating and relating your objects. The factories can get rather complex if you have a lot of object relationships to manage, but again, the logic is all kept in the factories. It's certainly possible for one factory to use another factory as well, so don't feel like you have to create a single uber-factory that does everything. And if or when you decide to try out another approach such as Transfer, you'll be happy you went the factory route. Good luck!

Comments Comments (1) | del.ico.us del.icio.us | Digg It! Digg It! | Linking Blogs Linking Blogs | 3580 Views

More Entries