July 16, 2003

Monkey Code

There's another MDA discussion at TSS, and it has prompted this longer-than-usual post on Monkey Code.

When I wrote this article, my main motivation was to cut the abstract, high-level, model-to-model transformation, meta-meta-model stuff and try to present the approach in a manner that would cause interest in the not-so-average, knowledgeable developer. Maybe I succeeded to some degree; but still I find it amazing that what is hardest is to convince people who usually "get it", not the managers or analysts.

Take a look at your usual J2EE application (just as an example - you can pick .NET or C++/CORBA or whatever you like as well). You have probably built it based on common knowledge about best practices, such as standard design patterns like those mentioned e.g. here or in books like this. In all of those patterns, you will find a description of how to take a business problem and turn it into an implementation.

The basic idea behind a pattern is to factor out common structural or behavioral aspects from a working solution so that they can be applied to similar problems. If you look at the code of your application, you will find that you do this, the degree depending on how strictly you follow a certain approach. This leads to an amazing level of redundancy, the reason being that you have flattened the patterns into an implementation that contains the pattern over and over again.

The easiest example is the get/set JavaBean pattern that we have become so used to we don't even recognize it. If you have a get and a set method and an attribute to hold the value, the semantic information is minimal - an attribute with a type, and possibly with a read/write option. This is a very small example, but the same is true on higher levels as well. Think about a conceptual entity in your business domain, e.g. a customer. The customer concept might be as simple as having a number of attributes, like name and basic address information, as illustrated by this pseudo-code:

  concept customer {
    attributes  {
        name: String;
        address: String;
        zipcode: String;
        country: String;
     }
  } 

Now think about how much code that simple concept is turned into. A standard architecture might have an entity bean implementation, local interface, local home interface, deployment descriptor; session facade bean, remote home, remote interface, value object and HTML form. All of these contain information that is dependent on the information of the customer concept.

That's what I call monkey code.

That is not to say that the implementation patterns - such as the standard J2EE design sketched out above - are simple, or even that such a thing as a default exists. They are a very important part of your architecture. But they are important only once.

Basically they are two things that are very interesting to spend time on - the business domain analysis and design, and the specification of how to map a business model to a specific platform. What's definitely not worth spending time on is doing the same thing over and over again. After all, that's what we have a computer for, isn't it?

Readers have left 6 Comments:
Comment from Mike Bresnahan at Feb 7, 2004 7:22 PM:

I couldn't agree with you more. Creating those umpteen classes each with umpteen getter and setter methods is plain silly, because the responsibility of each and every one of them can be summed up as "this class holds a set of name-value pairs and provides access to them". We can easily do the same thing with only one class, e.g. a Tuple class.

Comment from Stefan Tilkov at Feb 7, 2004 10:06 PM:

Thanks for your comment. I'd like to point out, though, that a generic (not generative!) solution has its own set of problems. I remember load of performance problems in projects that put attributes into a hashmap in the objects where they were then accessed with something like getAttribute("SomeAttrib") instead of getSomeAttrib(). This is an order of magnitude slower at the minimum. It's a good idea, as always, to aim for a balance between generative and generic solutions in your application.

Comment from Mike Bresnahan at Feb 8, 2004 9:06 AM:

True, getAttribute("SomeAttrib") is slower than getSomeAttrib(), but it still much faster that a database call or the generation of a HTML page. I have never found it to be a bottleneck. Generating the code is a happy medium in some ways, but I find it leads to the need to generate more code, which leads to the need to generate more code, etc... Although I have found successful ways to use Java reflection to mix the two paradaigms.

Comment from Stefan Tilkov at Feb 8, 2004 12:30 PM:

I'm not condemning this on principle: Whether the better approach for a given project is getSomeAttrib() or getAttribute() depends on the usage pattern. The getAttribute() way works very nicely for UI patterns, where you link an attribute name to a control. It sucks if you have complex algorithms that access the attribute multiple times. Combining code generation and genericity/reflection allows you to wrap one by the other - i.e., either have getSomeAttrib() call getAttribute("SomeAttrib") or the other way round. An MDA approach allows you to swap one for the other even when your application is done ...

Comment from Mike Bresnahan at Feb 8, 2004 6:41 PM:

Yup. And it also works well for many classes of data processing applications as well (data entry, ETL, etc), because 90-95% of the attributes are just traveling from place to another. There are few reasons to call getAttribute() on them. However, I would probably not use the generic approach in a real-time control system. How does MDA allow you to swap implementations after the application is done?

Comment from Stefan Tilkov at Feb 8, 2004 7:20 PM:

The basic idea is that you can separate your object model - let's say including the classes Customer, Address, Contract, Order - from a decision like whether you want to have attribute methods use a generic or a typed/named approach. Which of these approaches you use is specified in template rules; these are applied to the object model, yielding either one or the other result.
Since you can re-generate even after you have manually added code that is not being generated from the model, you have a big opportunity to try things out easily.

Post a comment (no HTML, please; http://... fragments will be turned into links automatically):









Remember personal info?