Monday, July 17, 2006

To Include Or Not To Include

I am always curious if other engineering disciplines can vehemently argue so much about fundamentals as we do? Do bridge engineers have heavy discussions about how much concrete is needed for a bridge pillar? Can they get into heated arguments if a skyscraper needs I reinforcement or not? In the information industry we can differ about the most fundamental approaches, everybody is an expert. Where are our universities testing the approaches and telling is what works and what does not? How could we more easily test ideas and decide about their value?

Why do I muse about this? Last week I had an argument with some experts that we could not decide. I lost because the owner of the problem decided to go another way while I strongly believed he was wrong. I’ll explain the problem and then you can figure out how to decide what the better approach should have been.

A couple of weeks ago I had to give a tutorial at ApacheCon Europe 2006. Obviously, I had to adapt my tutorial to use Apache Felix instead of Eclipse Equinox so I would not insult my hosts (or undergo the wrath of Richard Hall). Alas, Apache Felix does not yet have an implementation of declarative services. I therefore looked at several open source implementations and picked one to port. Declarative services require a framework specific implementation because it needs the Bundle Context of other bundles and there is no public function to do this in the specification. Bad, but we could not figure out in R4 how to do this in a secure way without using security. Now we know that you can not do secure things when security is not on, but that is another story.

So porting the declarative services was straightforward except for one snatch. To parse the Service-Component manifest header, the implementation used a utility function, which turned out to be implemented in the framework JAR. Not good. Looking at the parser, I decided that the easy way out was to write a simple replacement parser; the syntax for the Service-Component header is quite simple. The replacement code added about 6 lines to the implementation, making the declarative services bundle run on Felix without requiring any other supporting bundles.

After the tutorial I decided to submit my change as a patch, trying to be a good citizen. Great was my surprise when I started getting pushback. First, they felt that the parser was too simplistic; it ignored empty paths and did not detect syntax errors in the attributes. Personally that is fine by me, parsers should be lenient (though not creating erroneous values) and generators should be strict. However, this is again another story, many people feel more comfortable with rigid parsers for diagnostic reasons.

So I then redid the parser, discovering that the Service-Component header did not even support attributes! I threw the right exceptions on empty paths and discovered that Service-Component allowed quotes! Interestingly, the original manifest parser was thus not suited for this header at all.

After submitting my second patch, my expectation to be the hero now was again not honored. They still did not like it. Why? There was now a redundancy in the system; there were now two manifest parsers (despite that the original was wrong). They were therefore not willing to accept my patch. Instead, they will update their central manifest parser to support the Service-Component header quotes and reject attributes. Why? They did not like the redundancy.

This obviously did not fix my coupling problem whatsoever. I am a strong believer in least amount of coupling. In the OSGi build system I have addressed exactly this problem by copying the class files of utilities from the class path into the JAR; by making the packages private I prevent any version clashes. This gives me a single source without lots of utility bundles. The disadvantage is of course that if you find a bad bug, you must update all the bundles that contain that code. In my experience this is rarely much different from a shared bundle. State of the art version handling is so brittle that it is likely that all dependent bundles require an update to make the system resolve with the new utility bundle. And even if they require an update, the difference between updating one bundle or several bundles is not that big. It can even be questioned if you want to update the dependent bundles, often they do not really need the bug fix.

However, in the manifest parser case, I would personally gladly have accepted the source code redundancy; the new “improved” parser was only 15 lines. Yes, it is redundant, but the chance that you have an error in this code is pretty minute after testing and review.

And this is the point I want to discuss after this long introduction. We must balance redundancy (bad) versus coupling between bundles (bad). Redundancy is bad because it means we sometimes have to fix bugs or make improvements in multiple places. Coupling is bad because it makes the deployment situation more complex. The fact that today we are starting to handle dependencies does not mean dependencies have become benign. They can still bite you unexpectedly and mean. So how do we balance two bads? How do we decide which is the least bad?

Peter Kriens

5 comments:

  1. This is a great discussion to start but I must come to my own defense with respect to the handling of the bug you opened against Equinox. The bug is not been closed yet!! No decisions on a solution have been made. You seem to have jumped the gun on your comments on how we handle defects in Equinox.

    We completely understand your points and I even stated that in the end your solution may be the simplest thing to do in the bug report. You found a bug in our existing header parser. Of coarse we are going to fix that bug. I opened a separate bug to address that issue so we do not confuse that fix with the final desision we make with respect to the DS header parser. But that separate bug fix is not the solution to your issue.

    Aside from this the public OSGi Alliance blog seems like the wrong place to argue about how a particular bug is resolved in a particular open source project. Can you please add your comments to the bug report so we can work together toward the proper solution in Equinox.

    With that said, I do not think your main point for this blog entry is to discuss how Equinox bugs are handled. But that is hard to tell since you seem to talk about this for more than half of the entry. I guess this adds to the point you made in the first paragraph about how engineers like to argue ;-)

    ReplyDelete
  2. I would just add that redunancy is bad not just for the bug fix issue, but for some of us that work in the resource constrained embedded world, having multiple copies of classes is also a definite negative.

    Also, your blog seems to behave strangely with respect to comments. The home page says "0 comments" yet when I click to leave one I can see that there are already 2 other comments.

    ReplyDelete
  3. The blog does not mention that the DS came from Eclipse. I tried to discuss the issue how our industry lacks objective measurements for good and bad solutions. We all have "feelings" of what is good and what is bad and they sometimes clash. I wonder if other industries have the same issue. Such discussions are more lively based on real cases.

    ReplyDelete
  4. Byron,
    I agree that redundancy is bad, not only for resource constrained devices. Since at least 5 years ago I wanted to get a patent on this issue. It is trivial for an OSGi framework to put all the classes of all the bundles in a highly optimized "database". This database could easily remove any redundancy issues on the device itself. I never got around to do it and probably would have been forced to pledge it today :-) However, I still believe that an optimized OSGi framework can do wonders in this area without introducing unnecessary dependencies.

    Yes, comments act weird. I reindexed them all. Hope this helps.

    ReplyDelete

Blog Archive