October 30, 2011

Observer: Part II - Degenerated Observer


This is continuation from Observer: Part I - How to mess up your code with it.

In the previous part, I demonstrated some problems caused by a poor implementation of the Observer Pattern. In this and the next parts I am going to use the same Koala Zoo example to demonstrate how to implement it better.

Today we will be lazy and try to avoid implementing the pattern altogether.


Do it better - Degenerate the pattern

Often what we see is not a need for the full-fledged Observer Pattern, but a possible future need for it. In those cases, just save yourself some time and trouble and do not implement the pattern yet. Prepare for the need, but leave the implementation for the future.

Let's see how the Koala would be implemented using that mindset:
    public class Koala {
        private KoalaObserver keeper;

        public void setHungry(final boolean isHungry) {
            if (keeper != null) {
                keeper.koalaUpdate(this, isHungry);
            }
        }

        public void setObserver(final KoalaObserver keeper) {
            this.keeper = keeper;
        }

        @Override
        public String toString() {
            return "koala";
        }
    }

Instead of inheriting from the java.util.Observable, we now implement a very degenerated version of Observable ourselves.

As we need only one Observer we implement method setObserver, instead of addObserver. We do not provide method for deleting the Observer, unless we really need that. There is no change detection either. Just implement the bare minimum.

But we do need the interface for the KoalaObserver:
    public interface KoalaObserver {
        void koalaUpdate(Koala koala, boolean isHungry);
    }

Note that we are now able to pass on the information with correct types. Instead of two Objects, we are passing the Koala and a boolean telling whether the Koala is hungry. If you would need to pass more information, a good rule of thumb is to have maximum of four parameters in a method. So you might add two more parameters, like isAngry and isSick, but after that you should really refactor your code and implement a KoalaChangeEvent that would contain the parameters that need to be passed.

Now we are ready to implement the actual Observer:
    public class ZooKeeper implements KoalaObserver, WaterPipeObserver {

        @Override
        public void koalaUpdate(final Koala koala, final boolean isHungry) {
            if (isHungry) {
                LOGGER.info("Oh, the "
                        + koala
                        + " is hungry. I'll go into the cage and give" 
                        + " some eucalyptus to the little fella!");
            }
        }

        @Override
        public void pipeFixingNeeded() {
            LOGGER.info("Gonna fix the pipe now!");
        }
    }
Now the class declaration nicely tells us what entities the ZooKeeper is observing. I added the WaterPipe from the previous posting to demonstrate how all the different updates no longer go to a common update method. We are free to invent method names that really describe what is happening.

Last, here is how you would use the classes:
    public void testKoalaGetsFood() {
        final LogMsgCaptor logMsgCaptor = new LogMsgCaptor(LOGGER);
        final Koala koala = new Koala();
        final ZooKeeper zooKeeper = new ZooKeeper();

        koala.setObserver(zooKeeper);
        koala.setHungry(true);
        assertEquals(
                "The koala should get food",
                "Oh, the koala is hungry. I'll go into the cage and give" 
              + "some eucalyptus to the little fella!",
                logMsgCaptor.getMsg());
    }

If you now tried to do similar mistakes that we did in part I you would get compilation errors.
As you can see, methods are more descriptive and it is easier to see what each of the classes do just by looking at the classes themselves.

Overall, this degenerated pattern offers several advantages compared to using java.util.Observable and java.util.Observer. We have less functionality to maintain. Code is easier to read and debug. We get compilation errors if we break the pattern.


Pitfalls

There are two pitfalls here.

1. Skipping the interface

If you are a beginner, you might be tempted to skip the interface and just implement setKeeper(ZooKeeper keeper) method in the Koala. Do not do that - do not trust the Koala

The Koala or any Observable is not supposed to have full access to its Observer. Eventually someone is going to add some methods to the ZooKeeper that are too tempting for the Koala, like tieYourShoeLacesTogether. No Koala would miss that one. Even if you can keep yourself from calling those methods, the future maintenance person will not hesitate. If he can do something, he will.

2. Forgetting to synchronize when refactoring the code

Sometimes you do need to refactor the code later and add a list of Observers. You might be tempted to just add a List to hold the Observers and be done with it. Do not do that! The full-fledged Observer Pattern implementation needs synchronization.


Can you really do that? You'll have to implement the Observer Pattern sooner or later!

Well, it depends on the case. I have been using this deprecated pattern for over 5 years. I can still count with my one hand fingers the times that I needed to refactor the code to use a real Observer Pattern. Usually people have great plans for the future, but they never get implemented. You should prepare for the future, but never implement things that are not really needed now.

In most cases the Observable does just fine with one Observer. Sometimes there are cases where more Observers are needed, but this degenerated pattern is easily updated by storing the observers in a list and adding addObserver method. That will work as long as the Observers are added during initialization and synchronization is not needed. And with the Collections.synchronizedList(List list) you will add the synchronization in a minute, if needed.

Sometimes you will have a case where the Observers are added and removed on the fly from different threads and you need to make conditional notifications and/or store different types of Observers. Those cases are rare, but sometimes do happen. For those ones, you need a more complete implementations of the pattern. Let's take a look at those in the next parts.

October 29, 2011

Who is my Koala keeper?



This post contains answers to the puzzler presented in my previous post Observer Pattern: Part I - How to mess up your code with it.


All the code presented in the previous post is here:



What was wrong with the code?

There were 3 things wrong with the code:
  1. The WaterPipe is not getting fixed
  2. The Boss is observing the Koalas, but when they are hungry, all he does is complain
  3. Whenever the ZooKeeper feeds a Koala, the Boss is notified twice


Was the Boss supposed to observe the Koala?

Well, we have no way of knowing for sure just by looking at the code. I try to avoid puzzles with no clear answer in the future, but there was no going around for this one. When you do not type strictly, you just miss the information in the code if something goes wrong.

The initial though you probably had is that it probably is a mistake to add the Boss as the observer for the Koala, because he does not have the Koala-feeding code in his update method. But you cannot know for sure.

It is also possible (though not probable) that, for example, the Boss was supposed to feed the Koalas while the ZooKeeper is on vacation, but the implementation was never completed. We would need to search through the code and try to find if ZooKeeper ceases to observe the Koalas at some point. If we find such a code, we must fix the Boss so that he can feed the Koalas. If the ZooKeeper is available all the time, we can assume that the Boss should probably not be observing the Koalas. 



Could something like this really happen? Why would someone code something like this?

Yes, and no. 

The broken pipe was my own addition. As we do not have a complex subject and 10.000-50.000 lines of code here, I needed some distraction for you. I do not think it is a common mistake to totally mix up the observers like that. That type of mistake is possible, but as the pipe-fixing functionality would stop working altogether, it would be caught in the testing quite fast and thus the error would not survive long. 

But what happened with the Boss is real. I have fixed a similar bug. One of the nasty things about this pattern implementation is that the only reference to update method is in the java.util.Observable. The codebase had about 10 different Observers and I had to check through them all while I tried to find out who should observe who. Only after that was clear, was I able to concentrate on trying to find out what is wrong. The update method having and argument of Object array with four unknown Boolean and Integer parameters did not help either. 

Finally I came into conclusion that probably the Boss and the ZooKeeper had originally both been observing the Koala. At some point someone had thought that it is better that the ZooKeeper keeps the Boss informed. And while he remembered to remove the Koala-feeding code from the Boss, he did not remember that the Boss was still added as Observer for Koalas. We were getting quite a lot of extra notifications! 

While the similar situation could have occurred with better implementation of the Observer Pattern, it could not have happened by mistake. If strict types would have been used, the programmer would have gotten a compilation failure for trying to add the Boss as an observer for Koala.

In the next part of this series, I'll show you better ways to implement the Observer Pattern.





October 22, 2011

Observer: Part I - How to mess up your code with it


The Observer pattern is one of the patterns published in the Design Patterns book by the Gang of Four. It is needed when you have an object that changes it's state and you want other objects to notice the change.

If you are programming Java user interfaces you cannot really avoid this pattern. The whole Java event handling is based on it. So whenever you are writing event listeners for Swing components, you are actually using this pattern.

But Java also offers an implementation of the Observer interface and an Observable class to go with the interface. The problem with the Java Observer and Observable is that they were written before the Generics and so they use plain Objects to pass information. While that is not a problem in small hobby projects, it may lead to disasters in larger applications.


If you want to create easily maintainable code, you need to enforce the strong type checking that Java offers.

I guess most of you have heard that before. But maybe some of you have not seen what may happen when that rule is broken. And that is what I am about to demonstrate today. This is a beginner-level article. If you have already messed up your code by violating the rule and always try to avoid casting objects in your code, you might want to just quickly browse through the code and read the puzzler at the end of the post.


How to mess up your code with Java Observer

I am going to demonstrate the problem with a simple example from the Koala Zoo. In the very first version of the Koala Zoo we have just a Koala and a ZooKeeper, who gives food to the Koala when it is hungry.

Let's start by implementing the Koala using the Java Observable:
    public class Koala extends Observable {

        public void setHungry(final boolean isHungry) {
            setChanged();
            notifyObservers(isHungry);
        }

        @Override
        public String toString() {
            return "koala";
        }
    }

There we go! In real life the Koala class would probably be a bit more complex, but this is enough for our purposes. As you notice, Observable is a class and needs to be extended by our Koala.

Let's continue and create our Observer, the ZooKeeperObserver is an interface with a single method for getting updates from the Observable:
    public class ZooKeeper implements Observer {

        @Override
        public void update(final Observable animal, final Object arg) {
            if (arg instanceof Boolean) {
                final boolean isHungry = (Boolean) arg;
                if (isHungry) {
                    LOGGER.info("Oh, the " + animal
                            + " is hungry. I'll go into the cage and "
                            + "give some eucalyptus to the little fella!");
                }

            }
        }
    }

Our Observable and Observer are ready to go, let's test how they work:
    public void testKoalaGetsFood() {
        final LogMsgCaptor logMsgCaptor = new LogMsgCaptor(LOGGER);
        final Koala koala = new Koala();
        final ZooKeeper zooKeeper = new ZooKeeper();

        koala.addObserver(zooKeeper);
        koala.setHungry(true);
        assertEquals("The zookeeper should get notified",
                "Oh, the koala is hungry. I'll go into the cage and "
                        + "give some eucalyptus to the little fella!",
                logMsgCaptor.getMessage());
    }

LogMsgCaptor is a Mockito-based helper class that I wrote to collect logged messages so that I can test what was logged. Assert.assertEquals comes from JUnit and it makes our test case fail if the message logged does not match to what we expected.

As we can see, the code works nicely and ZooKeeper is able to keep the Koala stuffed with eucalyptus. But things are going to change when the code evolves.

The Zoo is growing and getting new animals. Introduce the Tiger!
    public class Tiger extends Observable {

        public void setHungry(final boolean isHungry) {
            setChanged();
            notifyObservers(isHungry);
        }

        @Override
        public String toString() {
            return "tiger";
        }
    }

At this point I might spare a thought on whether I could use a common superclass called Animal. But as it's easy to refactor later and pull the methods up, I am not going to do that now.

The Tiger observable is ready to use, but we have not made any changes to our Observer, the ZooKeeperThe nasty thing is that we can actually add the ZooKeeper as an observer for Tiger already and we get no compilation errors when we compile the code. Huh? The ZooKeeper is an observer for Koala, and as the update method is passing Objects as arguments, compiler have no way to know that the method is not implemented properly.

That means we need to REMEMBER to update the ZooKeeper's update method, so that he knows how the Tiger needs to be feed. But hey, that's no problem at all. I have great memory! If I sometimes forget my keys or the dinner or my pants or something it is just because I am thinking something else. But enough blabbering, let's have a coffee break. I suggest you to have a cup too!

Are you back yet? Where were we? Yeah, the Tiger. Let's continue and implement our new test case, the one where the ZooKeeper is feeding the Tiger:
    public void testTiggerGetsFood() {
        final LogMsgCaptor logMsgCaptor = new LogMsgCaptor(LOGGER);
        final Tiger tigger = new Tiger();
        final ZooKeeper zooKeeper = new ZooKeeper();

        tigger.addObserver(zooKeeper);
        tigger.setHungry(true);
        // As this test goes through OK, we forgot to update the ZooKeeper 
        assertEquals("Hmmm. Should the zookeeper go into the cage?",
                "Oh, the tiger is hungry. I'll go into the cage and "
                        + "give some eucalyptus to the little fella!",
                logMsgCaptor.getMessage());
    };
Oh well, what do you know... I'll fix the code in a minute...

I know that at this point some of you are thinking that this is not a big deal. But as time goes by and code gets filled up with little slips like the one I made above, results can be... interesting.

Let me show you an example with a little puzzler.


Puzzler: Koala Zoo after 2 years

The application has expanded and the Zoo now has new personnel. The ZooKeeper has been changed, and he has a Boss to report to:
    public class Boss implements Observer {

        @Override
        public void update(final Observable observable, final Object arg) {
            if (observable instanceof ZooKeeper) {
                ((ZooKeeper) observable).getStatusReport();
            }

            LOGGER.info("I hate being bugged with little things");
        }

    }

We can see that the ZooKeeper has become Observable too. Here is the new code for the ZooKeeper:
    public class ZooKeeper extends Observable implements Observer {

        public void getStatusReport() {
            LOGGER.info("Well, I have taken care of everything");
        }

        @Override
        public void update(final Observable observable, final Object arg) {
            final boolean argIsTrue = Boolean.TRUE.equals(arg);
            if (observable instanceof Koala && argIsTrue) {
                LOGGER.info("The lazy critter is hungry again, I cannot believe how much it eats");
            }
            else if (observable instanceof WaterPipe && argIsTrue) {
                LOGGER.info("I'll do what needs to be done");
            }

            if (argIsTrue) {
                setChanged();
                notifyObservers();
            }
        }
    }

Oh, it seems that the ZooKeeper now observers a WaterPipe too. But what is the argument? Lets check that out the WaterPipe to find out:
    public class WaterPipe extends Observable {

        public void setBroken(final boolean isBroken) {
            setChanged();
            notifyObservers(isBroken);
        }

        @Override
        public String toString() {
            return "watering system";
        }
    }

Oh, the argument is telling if the pipe is broken!
Let's see how all these classes are used:
        final List fifteenKoalas = initKoalas();
        final WaterPipe pipe = new WaterPipe();
        final ZooKeeper zooKeeper = new ZooKeeper();
        final Boss boss = new Boss();
        zooKeeper.addObserver(boss);
        pipe.addObserver(boss);

        for (final Koala koala : fifteenKoalas) {
            koala.addObserver(boss);
            koala.addObserver(zooKeeper);
        }

And as you might guess, this code is not working.

What is wrong and how would you fix it? Is the Boss supposed to observe the Koalas?

I'll tell you the answers in the next post.




October 15, 2011

Introduction and policy

This blog will contain little lessons about things that may cause problems in the context of larger code-bases. I will present you coding mistakes, bad practices and a way to implement the same thing in a better way. I will also present you some patterns that are widely promoted, but are often implemented badly by beginners. I will present stuff that is just fine in little home projects or school-work, but in the bigger projects cause a major headache in the future for the maintenance person. 

I am a Java specialist with over 10 years of experience in working with large code-bases. I have started some of those myself from the scratch, some I have just maintained. But in every case there has been so much to learn. 

The best way of learning is by mistake. Most of the stories told here are based on my own mistakes and bad practices. However, our own mistakes and bad habits are often invisible for us, at least for the first 1-2 years after the program has been made. Thus, I would never have learned so much without my dear colleagues. If you know me and see a mistake that was made by you, be proud. You have helped me to learn, and now you are helping others to learn.  

There is a companion code-base for this blog, called beyondhc. All the code snippets and classes presented in this blog can be found there. As most of the large code-bases are commercial, the code is published with Eclipse Public License 1.0 so that you may really use what you find. 

I respect my employer and do not use any project code in this blog. As the stories are based on what I have learned while working, the classes may have some resemblance to existing project code (dead or alive). But I assure that any such resemblance is purely coincidental. Each and every class presented here is written from the scratch - nothing is copied from existing projects.

And one last thing. I am not going to publish regularly, no-no. I'll just publish when I have something new to say. However, once I start a new series, you may expect the next parts to appear maybe once in a week (or two weeks) until the series is finished.