September 30, 2003

The problem with "Half Beans"

In an entry titled "Functional style in Java", Brian Slesinsky presents a technique he calls "half beans".

Never mind the fact that I can't really see the connection between this and functional programming, I find his recommendations quite questionable.

Brian is trying to solve the problems of objects that are not quite completely initialized.  In order to make sure an object is fully initialized, he forces his class (Album) to have just one constructor that accepts only one parameter, of type AlbumBuilder.  AlbumBuilder is the helper class in charge of making sure the object will be fully initialized.

There are a number of issues with his points.

  • First of all, the name.  I initially assumed that "half bean" meant that the pattern is supposed to avoid those "half beans", those Java Beans that are not completely initialized.  Well, no.  Half in this case means that the getters are in the main class and the setters and no-op argument are in the Builder class.  And to validate his point, Brian makes the following parallel:
    The getters go into one class and the no-arg constructor and setters go in the other. If it looks familar, you're right - it's basically the same pattern as String/StringBuffer.
    String and StringBuffer certainly have no such connection.  They are two very separate classes and one just happens to use the other for its internal implementation, but that's just a detail.  They could happily live separately and would serve a purpose on their own, as opposed to the Album/AlbumBuilder duo.
     
  • Second, all the AlbumBuilder class does is postpone the problem.  Instead of making sure that Album is fully initialized, you must now put this logic in AlbumBuilder.
     
  • And finally, this technique introduces a lethal weakness in the application by coupling the classes Album and AlbumBuilder in ways that are not only invisible to the programmer but invisible to the compiler as well.  For example, if one day, the design mandates the addition of a field "Producer" to the Album class, I have to remember to update AlbumBuilder or everything will break.

Overall, this technique doesn't help you address the main problem which, in my opinion, is not where you should signal the error but rather how you should handle it.  It is much more important to decide whether such an error should be an AssertionError, or an IllegalArgumentException or something else, and more importantly, whether it should be recoverable or not.

On a related note, the initial motivation that made Brian come up with this design was the absence of named parameters in Java:

Some languages solve this problem with keyword arguments, but Java doesn't have them, so we need another solution.

It is actually quite easy to emulate named parameters in Java.  For example:

new Album().title("The Wall").band("Pink Floyd");

This is very much un-Java, but it's there if you decide you need it one day.

Posted by cedric at September 30, 2003 08:29 AM
Comments

Hmm .. multiple classes that you need to keep in sync and that generally just "postpone the problem" .. are you talking half-beans or EJ beans? ;-)

Posted by: Cameron at September 30, 2003 09:24 AM

If this isn't the correct solution... what is? How do you handle when you need to pass 20 parameters into an object? I don't think having a constructor with 20 parameters makes sense.

Posted by: Andy at September 30, 2003 09:58 AM

"I don't think having a constructor with 20 parameters makes sense."

Just use getters and setters and unit test. If the data isn't there when you go to use it, throw a NullPointerException. It's a lot simpler than maintaining overloaded constructors or builder classes.

Posted by: Bob Lee at September 30, 2003 10:43 AM

If using getters/setters is okay, how do you handle methods that expect a primitive? You could use a boolean to see if this value was set or not, but that is a pain to code. You could require an object versus the primitive, but that is a pain to use. What is a better way?

If you use getters/setters, how do you verify that all of the required setters got called? If you create a verify method, do you call it every time that someone calls one of the getters? If you do that, what happens if you are using the object as a VO?

Also, how do you make getter/setter based objects immutable and when is it okay to use constructors versus getters/setters to build up an object?

Posted by: Andy at September 30, 2003 01:14 PM

"If using getters/setters is okay, how do you handle methods that expect a primitive?"

private Integer mInteger = null;
public void setPrimitive(int primitive) {
mInteger = new Integer(primitive);
}

Voila! NullPointerException is your friend, believe it or not.

Posted by: Ryan Campbell at September 30, 2003 04:24 PM

Oh duh! Now that is elegant! Thank you!

So how you advise handling the immutable and validator questions?

Posted by: Andy at September 30, 2003 06:23 PM

I guess immutable objects won't have setters by definition, right? But they won't have huge constructors either, usually just small single argument ones.

As for the validator object (VO?) question, could you be more specific? Why won't using setters work in this situation?

Posted by: Ryan Campbell at September 30, 2003 08:38 PM

Well, the point here is to come up with a way to handle big, complicated immutable objects - to show that they can be more than just simple value objects.

See my weblog for more about this.

Posted by: Brian Slesinsky at October 1, 2003 12:40 AM

I think Andy was talking about Value Objects (VO)

Posted by: Markus at October 1, 2003 08:33 AM

"If you use getters/setters, how do you verify that all of the required setters got called? If you create a verify method, do you call it every time that someone calls one of the getters? If you do that, what happens if you are using the object as a VO? Also, how do you make getter/setter based objects immutable and when is it okay to use constructors versus getters/setters to build up an object?"

Unit tests. In regard to immutability, most times it's possible to make the setters package-protected.

Posted by: Bob Lee at October 1, 2003 10:40 AM

My own follow up posted here http://blogs.browsermedia.com/page/patrick/20031001#half_baked_beans

Posted by: patrick at October 1, 2003 10:46 AM

If you use package level protection, does that mean you use the same package for your DAO classes?

Posted by: Markus at October 1, 2003 12:22 PM

"If you use package level protection, does that mean you use the same package for your DAO classes?"

I do.

Posted by: Bob Lee at October 3, 2003 08:16 AM

blah

Posted by: test close at March 1, 2004 06:37 AM

I think the lack of confidence is taught to American kids at a much younger age than University, it starts in grade school when "self esteem" is valued more than true confidence and achievement. Predetermined outcomes, grade inflation, etc set a lot of people up for a harsh fall later when they are unshielded from reality...maybe making them more ripe for self-hatred later? Confidence comes from believing in yourself, and past accomplishments...if you have neither of those then you will either try harder, or come to hate those that do succeed, or are confident.
Search Google http://www.google.com/

Posted by: Google at November 14, 2004 02:13 PM

Yay!
Search Google http://www.google.com/

Posted by: Google at November 17, 2004 02:24 AM

Three phrases should be among the most common in our daily usage. They are: Thank you, I am grateful and I appreciate.

Posted by: prosolution at December 12, 2005 02:14 AM
Post a comment






Remember personal info?