Saturday, October 26, 2013

Too Many Parameters in Java Methods, Part 8: Tooling

The first seven posts of my series of dealing with too many parameters expected in Java methods focused on alternative approaches to reduce the number of parameters a method or constructor expects. In this eighth post in the series, I look at tools that help identify cases where too many parameters may exist and tools that help deal with that when it occurs.

There is really no hard rule for the number of parameters to a method or constructor that is too many. In many ways, it's a matter of taste and depends somewhat on what those parameters are, if they use custom types rather than primitives and repeated types, and whether there are optional parameters that might require null to be passed.

Robert Martin, in Clean Code, writes (page 40):

The ideal number of arguments for a function is zero (niladic). Next comes one (monadic), followed closely by two (dyadic). Three arguments (triadic) should be avoided where possible. More than three (polyadic) requires very special justification - and then shouldn't be used anyway.

Steve McConnell, in Code Complete, writes that developers should "limit the number of a routine's parameters to about seven" because "seven is a magic number for people's comprehension." I don't think there's any set maximum number of parameters, but seven does seem like a "rule of thumb" to rarely exceed and I do generally prefer a smaller number such as Martin's recommendation of fewer than three arguments.

"The Eye Test"

There is a common expression in sports talk and sports writing that some player or team "doesn't pass the eye test." My understanding of that expression is that it means that despite whatever positive statistics might be associated with that player or team, watching the player or team play leads one to believe that they are not as good as the statistics might indicate. In other words, in a way that is difficult to describe, the viewer feels the team or player is not as skilled as their statistics imply.

In many ways, software development has its own "eye tests" that tell us when certain things are better or worse than the "rules" imply. Despite this, we still have "rules" or general guidelines about what makes for a generally good software practice just as sports have statistics to attempt to contrast teams and players objectively. For example, in software, we might say that "fewer parameters is generally better than more parameters." Tooling's biggest limitation is that it cannot perform an "eye test" for us, but it can help us to identify potential areas for improvement. In other words, tooling can help report the "statistics" of the game or match, but we must pass our own judgment ("eye test") on what the tooling is reporting.

Static Analysis Tools

Static analysis tools can be used to automatically identify methods or constructors which might expect too many parameters. Once the methods and constructors with potentially too many parameters have been identified, the developer can apply the "eye test" to them to determine if corrective action should be taken.

PMD

PMD (with the humorous slogan "Don't Shoot the Messenger") is a "source code analyzer" that "finds common programming flaws" in a number of programming languages (including Java). One of PMD's rules is "ExcessiveParameterList" (LongParameterListRule in PMD 4.3 instead of ExcessiveParameterList). The PMD-provided action when this rule is triggered is to "try to group the parameters together" with a "a new object [that] should be created to wrap the numerous parameters" (see my post on parameters objects). Newer PMD documentation puts it this way, "Methods with numerous parameters are a challenge to maintain, especially if most of them share the same datatype. These situations usually denote the need for new objects to wrap the numerous parameters."

Any tool must have a specified number of parameters that is considered "too many." In PMD's case, that default number is 10. Note that this default minimum threshold for triggering the PMD rule is higher than Steve McConnell's recommendation of 7 maximum parameters and significantly higher than Robert Martin's recommendation of fewer than three parameters.

NetBeans PMD support is available via the PMD Plugin. NetBeans PMD support is also available via the Software Quality Environment Plugins. I covered this in the previous posts NetBeans 7 and Software Quality Environment and Configuring SQE Plugins in NetBeans 7. QAPlug-PMD is a similar plug-in for IntelliJ IDEA and PMD Eclipse is available for Eclipse.

Checkstyle

Like PMD, Checkstyle detects and warns about too many method and constructor parameters. Checkstyle is defined on its main web page as "a development tool to help programmers write Java code that adheres to a coding standard." Specifically, Checkstyle provides the ParameterNumber "check" with the description, "Checks the number of parameters of a method or constructor." In Checkstyle's case, the default "maximum allowable number of parameters" for a constructor or method is 7 (same number as Steve McConnell's recommendation).

Checkstyle can be used in conjunction with NetBeans using the Checkstyle Beans plugin. Like NetBeans PMD support, Checkstyle support in NetBeans is also available via the previously mentioned Software Quality Environment. The eclipse-cs plugin supports Checkstyle integration with Eclipse and Checkstyle-IDEA is a similar plugin for IntelliJ IDEA.

CodePro Analytix

CodePro Analytix is part of the Google Java Developer Tools and is described as "the premier Java software testing tool for Eclipse developers who are concerned about improving software quality and reducing developments costs and schedules." It includes Code Audit capabilities with one category of rules being "Program Complexity." One of these rules is the "Large Number of Parameters" rule. That rule's Summary is that "Methods should not have too many parameters" and its description is: "This audit rule finds methods that have more than the specified number of parameters. Methods that exceed this number are likely to be too complex. Consider moving some of the values and behavior associated with them into a separate class."

It is also worth noting that CodePro Analytix also supports a "Average Number of Parameters" metric for metrics reporting. This metric reports the average number of parameters per method, but does not include constructors.

NetBeans Java Code Metrics Hints

I've already mentioned NetBeans plug-ins for Checkstyle and PMD, but one of my favorite features in NetBeans is the numerous and highly customizable built-in NetBeans hints and inspections. NetBeans 7.4 introduces a whole new category of hints called "Java Code Metrics" and one of these new hints is the "Constructor declares too many parameters" hint. This hint is described as, "Reports constructor that take too many parameters. Constructors typically take more parameters than a regular method, especially when initializing a large object. Large number of parameters indicate a bad design. It's likely that yet more parameters will be added in the future, so creational patterns like Builder should be considered." I covered the application of the builder pattern and even discussed using NetBeans to refactor a builder in a previous post in this series.

Another newly added hint, "Method declares too many parameters," is described as, "Reports method that take too many parameters. Methods with large number of parameters indicate a bad design. It's likely that yet more parameters will be added in the future, so the parameters should be grouped into a Command Object, improving maintenance costs. Alternatively, the method could be refactored into several methods, each doing part of the task and requiring less parameters at input." This recommended approach is essentially the same as the parameters object approach I blogged about earlier in this series of posts.

All of the hints in the "Java Code Metrics" category of NetBeans 7.4 are disabled by default. In his blog post "Just How Messed Up Is My Code?," the "occasional" NetBeans blogger Geertjan Wielenga demonstrates how to configure the Java Code Metrics to be active.

The next screen snapshot demonstrates use of Java Code Metrics in NetBeans 7.4. This is configured by selecting "Source" followed by "Inspect..." (which will open the NetBeans 7.4 "Inspect" window)

When the drop-down next to the "Use" label and "Configuration" bullet is selected in the "Inspect" window, the choices indicated in the next screen snapshots are available.

For my demonstration purposes, I select "All Analyzes" and then click on the "Inspect" button. The next screen snapshot demonstrates the inspection/analysis in progress.

"Out of the box," the NetBeans Inspect mechanism finds a bunch of my code missing Javadoc statements, but does not flag the constructors and methods with too many parameters. To address this, I need to follow the steps in Geertjan's blog post. To do this, I can click on the Source | Inspect and select "Default" for "Configuration."

Selecting "Default" allows me to now click on the "Manage..." button and clicking on that button presents the "Configuration" window.

Clicking on the "Default" label leads to a drop-down from which "New..." can be selected.

I can name the new configuration "Java Code Metrics".

Clicking on the drop-down next to the "Analyzer" label allows me to select "NetBeans Java Hints" and selecting that option presents all of the NetBeans Java Hint by categories. The next screen snapshot shows that I can select the code metrics to be inspected.

The next screen snapshot indicates that I can select "Constructor declares too many parameters" as a checkbox and "Method declares too many parameters" as another checkbox.

With a new "Java Code Metrics" inspection, it is easy to now inspect for those particular concerns by clicking on the "Inspect" button.

Pressing "Inspect" to apply the newly created "Java Code Metrics" inspection, leads to results shown in the following screen snapshots. The first image shows the high-level results and following images show more specific details made available by clicking on the high-level results.

With all of the static analysis tools I've covered, one can adjust the number of parameters deemed "too many" for a constructor or method. This configuration is really easy with NetBeans's Java Code Metrics support. The next two screen snapshots demonstrate that these values are set for constructors and methods respectively in the same window where we checked the options we wanted inspected. The expanded window for each checked option includes definition of the inspection type and a field to select the applicable number of parameters.

It is nice to be able to easily change the number of parameters deemed unacceptable (or at least worth pointing out so that the "eye test" can be applied) because there is such widely differing opinions on what number is unacceptable.

As the last series of screen snapshots demonstrate, NetBeans 7.4 allows us to specifically inspect code for methods and constructors that have "too many parameters." As I have been writing this portion of this post, I'm reminded that NetBeans provides significant static code analysis support.

IntelliJ IDEA Inspections

IntelliJ IDEA provides inspections for ferreting out methods with too many parameters. The "Method with too many parameters" inspection is described as: "This inspection reports any instances of methods with too many parameters. Methods with too many parameters are a good sign that refactoring is necessary. Methods whose signatures are inherited from library classes are ignored by this inspection." This inspection allows the number of method parameters that is too many to be configured.

Other Static Analysis Tools

There are other tools besides the ones that I have already focused on that, through static analysis, identify and flag awhen a Java method or constructor accepts "too many parameters." These include Java Coding Standard Checker and Sonar. The existence of all these static analysis tools that identify "too many parameters" is evidence that having too many parameters can be a maintenance and readability problem.

Code Change Tools

The tools discussed so far in this post have been useful in analyzing code to find existing methods and constructors expecting too many parameters. Once identified, these constructors and methods can be manually changed/refactored to reduce the number of parameters with approaches such as the ones I've outlined in earlier posts in this series of too many parameters. Fortunately, there are some tools that can aid in these refactoring and new code generation efforts. Modern Java IDEs are particularly helpful in the refactoring and code generation efforts.

Refactoring

One of the my favorite approaches for dealing with too many parameters to a constructor is application of a builder. Fortunately, NetBeans provides the ability to automatically refactor code relying on numerous parameter constructor to use a builder implementation. I have blogged on this approach previously in posts Too Many Parameters in Java Methods, Part 3: Builder Pattern and NetBeans 7.2: Refactoring Parameterized Constructor As Builder. IntelliJ IDEA has a similar refactoring tool called Replace Constructor with Builder. The Builder Pattern Eclipse Plugin is available for Eclipse.

Code Generation

Some of my favorite approaches for dealing with too many parameters include writing new custom types and creating parameters objects. Modern Java IDEs are tremendous here, making generation of these classes and enums simple. It often takes only a few minutes to generate a complete class with appropriate toString(), hashCode(), and equals(Object) implementations. It's really difficult for one to argue that it's too "expensive" to write custom type classes and parameters object (command) classes given how easy they are to write with modern Java IDEs and their code generation capabilities.

Conclusion

The focus of this post has been on tools that are available to the Java developer for identifying places in Java code where methods and/or constructors expect too many parameters and on tools available for easily fixing these constructors and methods to accept a more reasonable number of parameters. There are several static analysis tools and IDEs that support rapid identification of constructors and methods that expect too many parameters and modern Java IDEs make refactoring and code generation quick and easy. The wide number of tools available for identifying the "too many parameters" issue is a reminder that this is in fact an issue worth fixing.

Monday, October 21, 2013

Too Many Parameters in Java Methods, Part 7: Mutable State

In this seventh post of my series on addressing the issue of too many parameters in a Java method or constructor, I look at using state to reduce the need to pass parameters. One of the reasons I have waited until the 7th post of this series to address this is that it is one of my least favorite approaches for reducing parameters passed to methods and constructors. That stated, there are multiple flavors of this approach and I definitely prefer some flavors over others.

Perhaps the best known and most widely scorned approach in all of software development for using state to reduce parameter methods is the use global variables. Although it may be semantically accurate to say that Java does not have global variables, the reality is that for good or for bad the equivalent of global variables is achieved in Java via public static constructs. A particularly popular way to achieve this in Java is via the Stateful Singleton.

In Patterns of Enterprise Application Architecture, Martin Fowler wrote that "any global data is always guilty until proven innocent." Global variables and "global-like" constructs in Java are considered bad form for several reasons. They can make it difficult for developers maintaining and reading code to know where the values are defined or last changed or even come from. By their very nature and intent, global data violates the principles of encapsulation and data hiding.

Miško Hevery has written the following regarding the problems of static globals in an object-oriented language:

Accessing global state statically doesn’t clarify those shared dependencies to readers of the constructors and methods that use the Global State. Global State and Singletons make APIs lie about their true dependencies. ... The root problem with global state is that it is globally accessible. In an ideal world, an object should be able to interact only with other objects which were directly passed into it (through a constructor, or method call).

Having state available globally reduces the need for parameters because there is no need for one object to pass data to another object if both objects already have direct access to that data. However, as Hevery put it, that's completely orthogonal to the intent of object-oriented design.

Mutable state is also an increasing problem as concurrent applications become more common. In his JavaOne 2012 presentation on Scala, Scala creator Martin Odersky stated that "every piece of mutable state you have is a liability" in a highly concurrent world and added that the problem is "non-determinism caused by concurrent threads accessing shared mutable state."

Although there are reasons to avoid mutable state, it still remains a generally popular approach in software development. I think there are several reasons for this including that it's superfically easy to write mutable state sharing code and mutable shared code does provide ease of access. Some types of mutable data are popular because those types of mutable data have been taught and learned as effective for years. Finally, three are times when mutable state may be the most appropriate solution. For that last reason and to be complete, I now look at how the use of mutable state can reduce the number of parameters a method must expect.

Stateful Singleton and Static Variables

A Java implementation of Singleton and other public Java static fields are generally available to any Java code within the same Java Virtual Machine (JVM) and loaded with the same classloader [for more details, see When is a Singleton not a Singleton?].

Any data stored universally (at least from JVM/classloader perspective) is already available to client code in the same JVM and loaded with the same class loader. Because of this, there is no need to pass that data between clients and methods or constructors in that same JVM/classloader combination.

Instance State

While "statics" are considered "globally available," narrower instance-level state can also be used in a similar fashion to reduce the need to pass parameters between methods of the same class. An advantage of this over global variables is that the accessibility is limited to instances of the class (private fields) or instances of the class's children (protected fields). Of course, if the fields are public, accessibility is pretty wide open, but the same data is not automatically available to other code in the same JVM/classloader.

The next code listing demonstrates how state data can and sometimes is used to reduce the need for parameters between two methods internal to a given class.

Example of Instance State Used to Avoid Passing Parameters
   /**
    * Simple example of using instance variable so that there is no need to
    * pass parameters to other methods defined in the same class.
    */
   public void doSomethingGoodWithInstanceVariables()
   {
      this.person =
         Person.createInstanceWithNameAndAddressOnly(
            new FullName.FullNameBuilder(new Name("Flintstone"), new Name("Fred")).createFullName(),
            new Address.AddressBuilder(new City("Bedrock"), State.UN).createAddress());
      printPerson();
   }

   /**
    * Prints instance of Person without requiring it to be passed in because it
    * is an instance variable.
    */
   public void printPerson()
   {
      out.println(this.person);
   }

The above example is somewhat contrived and simplified, but does illustrate the point: the instance variable person can be accessed by other instance methods defined in the same class, so that instance does not need to be passed between those instance methods. This does reduce the signature of potentially (public accessibility means it may be used by external methods) internal methods, but also introduces state and now means that the invoked method impacts the state of that same object. In other words, the benefit of not having to pass the parameter comes at the cost of another piece of mutable state. The other side of the trade-off, needing to pass the instance of Person because it is not an instance variable, is shown in the next code listing for comparison.

Example of Passing Parameter Rather than Using Instance Variable
   /**
    * Simple example of passing a parameter rather than using an instance variable.
    */
   public void doSomethingGoodWithoutInstanceVariables()
   {
      final Person person =
         Person.createInstanceWithNameAndAddressOnly(
            new FullName.FullNameBuilder(new Name("Flintstone"), new Name("Fred")).createFullName(),
            new Address.AddressBuilder(new City("Bedrock"), State.UN).createAddress());
      printPerson(person);
   }

   /**
    * Prints instance of Person that is passed in as a parameter.
    * 
    * @param person Instance of Person to be printed.
    */
   public void printPerson(final Person person)
   {
      out.println(person);
   }

The previous two code listings illustrate that parameter passing can be reduced by using instance state. I generally prefer to not use instance state solely to avoid parameter passing. If instance state is needed for other reasons, than the reduction of parameters to be passed is a nice side benefit, but I don't like introducing unnecessary instance state simply to remove or reduce the number of parameters. Although there was a time when the readability of reduced parameters might have justified instance state in a large single-threaded environment, I feel that the slight readability gain from reduced parameters is not worth the cost of classes that are not thread-safe in an increasingly multi-threaded world. I still don't like to pass a whole lot of parameters between methods of the same class, but I can use the parameters object (perhaps with a package-private scope class) to reduce the number of these parameters and pass that parameters object around instead of the large number of parameters.

JavaBean Style Construction

The JavaBeans convention/style has become extremely popular in the Java development community. Many frameworks such as Spring Framework and Hibernate rely on classes adhering to the JavaBeans conventions and some of the standards like Java Persistence API also are built around the JavaBeans conventions. There are multiple reasons for the popularity of the JavaBeans style including its ease-of-use and the ability to use reflection against this code adhering to this convention to avoid additional configuration.

The general idea behind the JavaBean style is to instantiate an object with a no-argument constructor and then set its fields via single-argument "set" methods and access it fields via no-argument "get" methods. This is demonstrated in the next code listings. The first listing shows a simple example of a PersonBean class with no-arguments constructor and getter and setter methods. That code listing also includes some of the JavaBeans-style classes it uses. That code listing is followed by code using that JavaBean style class.

Examples of JavaBeans Style Class
public class PersonBean
{
   private FullNameBean name;
   private AddressBean address;
   private Gender gender;
   private EmploymentStatus employment;
   private HomeownerStatus homeOwnerStatus;

   /** No-arguments constructor. */
   public PersonBean() {}

   public FullNameBean getName()
   {
      return this.name;
   }
   
   public void setName(final FullNameBean newName)
   {
      this.name = newName;
   }
   
   public AddressBean getAddress()
   {
      return this.address;
   }
   
   public void setAddress(final AddressBean newAddress)
   {
      this.address = newAddress;
   }

   public Gender getGender()
   {
      return this.gender;
   }
   
   public void setGender(final Gender newGender)
   {
      this.gender = newGender;
   }
   
   public EmploymentStatus getEmployment()
   {
      return this.employment;
   }
   
   public void setEmployment(final EmploymentStatus newEmployment)
   {
      this.employment = newEmployment;
   }

   public HomeownerStatus getHomeOwnerStatus()
   {
      return this.homeOwnerStatus;
   }

   public void setHomeOwnerStatus(final HomeownerStatus newHomeOwnerStatus)
   {
      this.homeOwnerStatus = newHomeOwnerStatus;
   }
}

/**
 * Full name of a person in JavaBean style.
 * 
 * @author Dustin
 */
public final class FullNameBean
{
   private Name lastName;
   private Name firstName;
   private Name middleName;
   private Salutation salutation;
   private Suffix suffix;

   /** No-args constructor for JavaBean style instantiation. */
   private FullNameBean() {}

   public Name getFirstName()
   {
      return this.firstName;
   }

   public void setFirstName(final Name newFirstName)
   {
      this.firstName = newFirstName;
   }

   public Name getLastName()
   {
      return this.lastName;
   }

   public void setLastName(final Name newLastName)
   {
      this.lastName = newLastName;
   }

   public Name getMiddleName()
   {
      return this.middleName;
   }

   public void setMiddleName(final Name newMiddleName)
   {
      this.middleName = newMiddleName;
   }

   public Salutation getSalutation()
   {
      return this.salutation;
   }
 
   public void setSalutation(final Salutation newSalutation)
   {
      this.salutation = newSalutation;
   }

   public Suffix getSuffix()
   {
      return this.suffix;
   }

   public void setSuffix(final Suffix newSuffix)
   {
      this.suffix = newSuffix;
   }

   @Override
   public String toString()
   {
      return  this.salutation + " " + this.firstName + " " + this.middleName
            + this.lastName + ", " + this.suffix;
   }
}


package dustin.examples;

/**
 * Representation of a United States address (JavaBeans style).
 * 
 * @author Dustin
 */
public final class AddressBean
{
   private StreetAddress streetAddress;
   private City city;
   private State state;

   /** No-arguments constructor for JavaBeans-style instantiation. */
   private AddressBean() {}

   public StreetAddress getStreetAddress()
   {
      return this.streetAddress;
   }

   public void setStreetAddress(final StreetAddress newStreetAddress)
   {
      this.streetAddress = newStreetAddress;
   }

   public City getCity()
   {
      return this.city;
   }

   public void setCity(final City newCity)
   {
      this.city = newCity;
   }

   public State getState()
   {
      return this.state;
   }

   public void setState(final State newState)
   {
      this.state = newState;
   }

   @Override
   public String toString()
   {
      return this.streetAddress + ", " + this.city + ", " + this.state;
   }
}
Example of JavaBeans Style Instantiation and Population
   public PersonBean createPerson()
   {
      final PersonBean person = new PersonBean();
      final FullNameBean personName = new FullNameBean();
      personName.setFirstName(new Name("Fred"));
      personName.setLastName(new Name("Flintstone"));
      person.setName(personName);
      final AddressBean address = new AddressBean();
      address.setStreetAddress(new StreetAddress("345 Cave Stone Road"));
      address.setCity(new City("Bedrock"));
      person.setAddress(address);
      return person;
   }

The examples just shown demonstrate how the JavaBeans style approach can be used. This approach makes some concessions to reduce the need to pass a large number of parameters to a class's constructor. Instead, no parameters are passed to the constructor and each individual attribute that is needed must be set. One of the advantages of the JavaBeans style approach is that readability is enhanced as compared to a constructor with a large number of parameters because each of the "set" methods is hopefully named in a readable way.

The JavaBeans approach is simple to understand and definitely achieves the goal of reducing lengthy parameters in the case of constructors. However, there are some disadvantages to this approach as well. One advantage is a lot of tedious client code for instantiating the object and setting its attributes one-at-a-time. It is easy with this approach to neglect to set a required attribute because there is no way for the compiler to enforce all required parameters be set without leaving the JavaBeans convention. Perhaps most damaging, there are several objects instantiated in this last code listing and these objects exist in different incomplete states from the time they are instantiated until the time the final "set" method is called. During that time, the objects are in what is really an "undefined" or "incomplete" state. The existence of "set" methods necessarily means that the class's attributes cannot be final, rendering the entire object highly mutable.

Regarding the prevalent use of the JavaBeans pattern in Java, several credible authors have called into question its value. Allen Holub's controversial article Why getter and setter methods are evil starts off with no holds barred:

Though getter/setter methods are commonplace in Java, they are not particularly object oriented (OO). In fact, they can damage your code's maintainability. Moreover, the presence of numerous getter and setter methods is a red flag that the program isn't necessarily well designed from an OO perspective.

Josh Bloch, in his less forceful and more gently persuasive tone, says of the JavaBeans getter/setter style: "The JavaBeans pattern has serious disadvantages of its own" (Effective Java, Second Edition, Item #2). It is in this context that Bloch recommends the builder pattern instead for object construction.

I'm not against using the JavaBeans get/set style when the framework I've selected for other reasons requires it and the reasons for using that framework justify it. There are also areas where the JavaBeans style class is particularly well suited such as interacting with a data store and holding data from the data store for use by the application. However, I am not a fan of using the JavaBeans style for instantiating a question simply to avoid the need to pass parameters. I prefer one of the other approaches such as builder for that purpose.

Benefits and Advantages

I've covered different approaches to reducing the number of arguments to a method or constructor in this post, but they also share the same trade-off: exposing mutable state to reduce or eliminate the number of parameters that must be passed to a method or to a constructor. The advantages of these approaches are simplicity, generally readable (though "globals" can be difficult to read), and ease of first writing and use. Of course, their biggest advantage from this post's perspective is that they generally eliminate the need for any parameter passing.

Costs and Disadvantages

The trait that all approaches covered in this post share is the exposure of mutable state. This can lead to an extremely high cost if the code is used in a highly concurrent environment. There is a certain degree of unpredictability when object state is exposed for anyone to tinker with it as they like. It can be difficult to know which code made the wrong change or failed to make a necessary change (such as failing to call a "set" method when populating a newly instantiated object).

Conclusion

Even some of the approaches to reducing parameters that I have covered earlier (such as custom types and parameters objects) can be implemented in such a way that there is (optional) mutable state, but those approaches do not require mutable state. In contrast, the approaches covered in this post to reducing parameters to methods and constructors do require mutable state.

Some of the approaches covered in this post are highly popular despite their drawbacks. This may be for a variety of reasons including prevalence of use in popular frameworks (forcing users of the framework to use that style and also providing examples to others for their own code development). Other reasons for these approaches' popularity is the relative ease of initial development and the seemingly (deceptively) relatively little thought that needs to go into design with these approaches. In general, I prefer to spend a little more design and implementation effort to use builders and less mutable approaches when practical. However, there are cases where these mutable state approaches work well in reducing the number of parameters passed around and introduce no more risk than was already present. My feeling is that Java developers should carefully consider use of any mutable Java classes and ensure that the mutability is either desired or is a cost that is justified by the reasons for using a mutable state approach.

Friday, October 18, 2013

Too Many Parameters in Java Methods, Part 6: Method Returns

In the current series of posts I am writing on reducing the number of parameters required to call Java methods and constructors, I have focused so far on approaches that directly affect the parameters themselves (custom types, parameters objects, builder pattern, method overloading, and method naming). Given this, it might seem surprising for me to devote a post in this series to how Java methods provide return values. However, methods' return values can impact the parameters the methods accept when developers choose to provide "return" values by setting or changing provided parameters rather than or in addition to more traditional method return mechanisms.

The "traditional ways" that a non-constructor method returns a value can both be specified in the method signature. The most commonly recognized approach for returning a value from a Java method is via its declared return type. This often works well, but one of frustrations that most commonly occurs is being allowed to return only one value from a Java method..

Java's exception handling mechanism is also another approach for retaining a "result" of a method to callers. Checked exceptions, in particular, are advertised to the caller via the throws clause. In fact, Jim Waldo, in his book Java: The Good Parts, states that it is easier to understand Java exceptions when one thinks of Java exceptions as another type of method return limited to being a Throwable type.

Although the method's return type and thrown exceptions are intended as the primary approaches for methods to return information to callers, it is sometimes tempting to return data or state via the parameters passed into the method. When a method needs to return more than one piece of information, the single-value returns of Java methods can seem limiting. Although exceptions provide another way to communicate back to the caller, it seems almost universally agreed that exceptions should only be used for reporting exceptional situations and not for reporting "normal" data or used in control flow. Given that only one object or primitive can be returned from a method and that exceptions only allow returning of a Throwable and should only be used to report exceptional situations, it becomes increasingly attractive for the Java developer to hijack parameters as an alternate route for returning data to the caller.

The technique that a developer can use to apply method parameters as carriers for return data is to accept parameters that are mutable and to mutate the passed-in objects' state. These mutable objects can have their contents changed by the method and then the caller can access the object it provided to determine its new state settings that have been applied by the called method. Although this can be done with any mutable object, collections seem particularly attractive to the developer trying to pass values back to the caller via parameters.

There are some disadvantages to passing state back to the called via the provided parameters. This approach often violates the principle of least astonishment as most Java developers probably expect parameters to be INcoming rather than OUTgoing (and Java doesn't provide any code support to specify the difference). Bob Martin puts it this way in his book Clean Code, "In general, output arguments should be avoided." Another disadvantage of using arguments as a means for a method to provide state or output to the caller is that this adds to the clutter of arguments passed to a method. With this in mind, the remainder of this post focuses on alternatives to returning multiple values via passed-in parameters.

Although Java methods can only return a single object or primitive, this is really not much of a limitation when one considers that an object can be just about anything we want it to be. There are several approaches that I've seen but don't recommend. One of these is returning an array or collection of Object instances with each Object being a disparate and distinct and often unrelated "thing." For example, the method might return three values as three elements of an array or collection. A variation of this approach is to use a pair tuple or n-sized tuple to return multiple associated values. One other variation on this approach is to return a Java Map that maps arbitrary keys to their associated value. As with the other solutions, this approach places undue burden on the client to know what those keys are and to access the map values through those keys.

The next code listing contains several of these less attractive approaches for returning multiple values without hijacking the method parameters to return multiple values.

Returning Multiple Values via Generic Data Structures
   // ===============================================================
   // NOTE: These examples are intended solely to illustrate a point
   //       and are NOT recommended for production code.
   // ===============================================================

   /**
    * Provide movie information.
    * 
    * @return Movie information in form of an array where details are mapped to
    * elements with the following indexes in the array:
    *       0 : Movie Title
    *       1 : Year Released
    *       2 : Director
    *       3 : Rating
    */
   public Object[] getMovieInformation()
   {
      final Object[] movieDetails =
         {"World War Z", 2013, "Marc Forster", "PG-13"};
      return movieDetails;
   }

   /**
    * Provide movie information.
    * 
    * @return Movie information in form of a List where details are provided
    * in this order: Movie Title, Year Released, Director, Rating.
    */
   public List<Object> getMovieDetails()
   {
      return Arrays.<Object>asList("Ender's Game", 2013, "Gavin Hood", "PG-13");
   }
   
   /**
    * Provide movie information.
    * 
    * @return Movie information in Map form. Characteristics of the movie can
    * be acquired by looking in the map for these key elements: "Title", "Year",
    * "Director", and "Rating"./
    */
   public Map<String, Object> getMovieDetailsMap()
   {
      final HashMap<String, Object> map = new HashMap();
      map.put("Title", "Despicable Me 2");
      map.put("Year", 2013);
      map.put("Director", "Pierre Coffin and Chris Renaud");
      map.put("Rating", "PG");
      return map;
   }

The approaches shown above do meet the intent of not passing data back to the caller via the invoked methods' parameters, but there is still unnecessary burden placed on the caller to know intimate details of the returned data structure. It's nice to reduce the number of parameters to the method and not violate the principle of least surprise, but it's not so nice to require the client to know the intricacies of a complex data structure.

I prefer to write custom objects for my returns when I need to return more than one value. It's a bit more work than using an array, collection, or tuple structure, but the very small amount of extra work (typically a few minutes with modern Java IDEs) pays off with readability and fluency that is not available with these more generic approaches. Rather than having to explain with Javadoc or require users of my code to read my code carefully to know which parameters are provided in which order in the array or collection or which value is which in the tuple, my custom return objects can have methods defined on them that tell the client exactly what they are providing.

The code snippets that follow illustrate a simple Movie class largely generated by NetBeans that can be used as the return type along with the code that could return an instance of that class rather than a more generic and less readable data structure.

Movie.java
package dustin.examples;

import java.util.Objects;

/**
 * Simple Movie class to demonstrate how easy it is to provide multiple values
 * in a single Java method return and provide readability to the client.
 * 
 * @author Dustin
 */
public class Movie
{
   private final String movieTitle;
   private final int yearReleased;
   private final String movieDirectorName;
   private final String movieRating;

   public Movie(String movieTitle, int yearReleased, String movieDirectorName, String movieRating)
   {
      this.movieTitle = movieTitle;
      this.yearReleased = yearReleased;
      this.movieDirectorName = movieDirectorName;
      this.movieRating = movieRating;
   }

   public String getMovieTitle()
   {
      return movieTitle;
   }

   public int getYearReleased()
   {
      return yearReleased;
   }

   public String getMovieDirectorName()
   {
      return movieDirectorName;
   }

   public String getMovieRating()
   {
      return movieRating;
   }

   @Override
   public int hashCode()
   {
      int hash = 3;
      hash = 89 * hash + Objects.hashCode(this.movieTitle);
      hash = 89 * hash + this.yearReleased;
      hash = 89 * hash + Objects.hashCode(this.movieDirectorName);
      hash = 89 * hash + Objects.hashCode(this.movieRating);
      return hash;
   }

   @Override
   public boolean equals(Object obj)
   {
      if (obj == null)
      {
         return false;
      }
      if (getClass() != obj.getClass())
      {
         return false;
      }
      final Movie other = (Movie) obj;
      if (!Objects.equals(this.movieTitle, other.movieTitle))
      {
         return false;
      }
      if (this.yearReleased != other.yearReleased)
      {
         return false;
      }
      if (!Objects.equals(this.movieDirectorName, other.movieDirectorName))
      {
         return false;
      }
      if (!Objects.equals(this.movieRating, other.movieRating))
      {
         return false;
      }
      return true;
   }

   @Override
   public String toString()
   {
      return "Movie{" + "movieTitle=" + movieTitle + ", yearReleased=" + yearReleased + ", movieDirectorName=" + movieDirectorName + ", movieRating=" + movieRating + '}';
   }
}
Returning Multiple Details in Single Object
   /**
    * Provide movie information.
    * 
    * @return Movie information.
    */
   public Movie getMovieInfo()
   {
      return new Movie("Oblivion", 2013, "Joseph Kosinski", "PG-13");
   }

The simple writing of the Movie class took me about 5 minutes. I used the NetBeans class creation wizard to select the class name and package and then I typed in the four attributes of the class. From there, I simply used NetBeans's "Insert Code" mechanism to insert "get" accessor methods along with overridden toString(), hashCode(), and equals(Object) methods. If I didn't think I needed some of that, I could keep the class simpler, but it really is easy to create as is. Now, I have a much more usable return type and this is reflected by the code that uses the class. It doesn't need nearly as much Javadoc comments on the return type because that type speaks for itself and advertises its content with its "get" methods. I feel that the small amount of additional effort to create these simple classes for returning multiple values pays off with huge dividends when compared to alternatives such as returning state via method parameters or using more generic and harder to use return data structures.

It is not too surprising that a custom type to hold the multiple values to be returned to a caller is an attractive solution. After all, this is conceptually very similar to the concepts I blogged about previously related to using custom types and parameters objects for passing in multiple related parameters rather than passing them all in individually. Java is an object-oriented language and so it surprises me when I don't see objects used more often in Java code for organizing parameters AND return values in a nice package.

Benefits and Advantages

The advantages of using custom parameter objects to represent and encapsulate multiple return values are obvious. Parameters to the method can remain "input" parameters because all output information (except for error information communicated via the exception mechanism) can be provided in the custom object returned by the method. This is a cleaner approach than using generic arrays, collections, maps, tuples, or other generic data structures because all of those alternative approaches shift development effort onto all potential clients.

Costs and Disadvantages

I see very little downside to writing custom types with multiple values to be used as return types from Java methods. Perhaps the most often claimed cost is the price of writing and testing these classes, but that cost is pretty small because these classes tend to be simple and because modern IDEs do most of the work for us. Because the IDEs do it automatically, the code is typically correct. The classes are so simple that they are easily readable by code reviewers and they are easy to test.

Stretching to find other costs and disadvantages, one might argue that these classes can bloat code bases and packages, but I don't see that as a strong argument. Although there may be a very small risk of a badly implemented custom class, I think the chance of client code messing up interpretation of a more generic return type is more likely to occur. One other small risk is that developers might throw a lot of unrelated stuff into the same class with the only relationship between those items being the fact that the same method needs to return them. Even with this, the only better alternative I can see would be to modify the code to not need to return multiple values. Returning otherwise unrelated items in a custom object still seems better than returning this set of unrelated data in a generic data structure. In fact, those generic data structures become more unwieldy and difficult to use as the values which they hold become less related.

Conclusion

Custom types and parameters objects help us directly address the problem of too many parameters to a Java method. Fortunately, these custom types and return values objects can also help us indirectly reduce our number of required parameters by allowing us to return multiple values through the custom types and return values objects rather than needing to add additional parameters meant only to convey output information back to the caller.

Thursday, October 17, 2013

Too Many Parameters in Java Methods, Part 5: Method Naming

In my previous post (Part 4 of my series on dealing with too many parameters in Java methods), I looked at method overloading as one approach to providing clients with versions of methods or constructors requiring fewer parameters. I described some disadvantages of that approach and suggested that breaking loose from method overloading to use differently named methods could at least partially address some of these disadvantages. In this post, I look more deeply at how careful naming of methods (including construction methods) can be used to remove lengthy parameters lists and avoid some of the issues with method overloading.

From the perspective of reducing the number of parameters required in method and constructor calls, some of the most significant issues associated with method overloading surround a limitation of how many times the same method name can be overloaded for a large set of parameters, especially if some of the parameters share the same data type. For example, if I have a class with three String attributes and want to write three constructors to accept only one of these attributes each, I really cannot do this with method overloading. If I tried, the constructor accepting a single String would have to be used for one of the three attributes and only a Javadoc comment could explain which of the three attributes that single-argument constructor sets. Breaking loose from the limitation of using the same name for all methods and construction methods allows one to be more expressive in code regarding the expected and assumed parameters.

The following code listing contains some examples of various methods for asking an independent class (not the Person class) to provide an instance of Person (a class referenced in my earlier posts on too many Java parameters). These methods have lengthy names that describe much about what is expected in the parameters. This means that less needs to be described in Javadoc comments, methods' invocations are more readable to clients, and there are more possibilities and permutations of parameters that can be supported than by method overloading.

Examples of Instance Methods Named to Describe What They Do
   public Person createPersonWithFirstAndLastNameOnly(final String firstName, final String lastName)
   {
      // implementation goes here ...
   }

   public Person createEmployedHomeOwningFemale(final FullName name, final Address address)
   {
      // implementation goes here ...
   }

   public Person createEmployedHomeOwningMale(final FullName name, final Address address)
   {
      // implementation goes here ...
   }

   public Person createUnemployedHomeOwningFemale(final FullName name, final Address address)
   {
      // implementation goes here ...
   }
   
   public Person createEmployedRentingMale(final FullName name, final Address address)
   {
      // implementation goes here ...
   }

The longer method names shown in the code above are descriptive and provide the client a good head start in knowing what parameters to provide. Of course, I could have written many more methods like those above to cover the various permutations of parameters, but the small set I did list cover the point. Notice that I also used parameters objects (FullName and Address defined in my post on parameters objects) in these code examples to reduce the number of parameters further.

My code examples above demonstrated providing different and descriptive names for instance methods to imply what parameters to pass and to even in some cases imply which parameters do not need to be provided because they are implied in the method name. Those new to Java might think this approach cannot be used with object instantiation/construction because Java class constructors must be named with the same name as the class. This implies that constructors can only be overloaded based on method signature. Fortunately, Josh Bloch addressed this in the very first item of both editions of Effective Java. As Bloch describes there, we can employ static initialization factory methods to provide instances of our classes. One of the benefits Bloch cites in this Item #1 is the ability to name these methods as we see fit.

The next code listing demonstrates the power of these static initialization factories. When I implement these, I like to implement one or a very small number of private constructors (cannot be instantiated by external classes) that are called only by my static initialization factories. This allows me to leave the constructor's method signature as potentially a little less than desirable because only my class must use it and the static initialization factories others use are easier to use and hide the ugliness of the many parameters constructor. More specifically, if the constructor takes null for optional parameters, I can write various static initialization factories so that my clients don't need to pass null, but my factory methods can instead pass the null to the constructor. In short, static initialization factory methods allow me to present a cleaner, more pleasant interface to clients and hide ugliness in the internals of my class. I cannot as easily provide this with multiple constructors directly because of the inability to name them anything with explanatory detail. Another advantage of these static initialization methods is that I can have them accept "raw" types if desired and build these into custom types and parameters objects internally. All of these cases are shown in the next code listing.

Static Initialization Factories Demonstrated
   /**
    * Parameterized constructor can be private because only my internal builder
    * needs to call me to provide an instance to clients.
    * 
    * @param newName Name of this person.
    * @param newAddress Address of this person.
    * @param newGender Gender of this person.
    * @param newEmployment Employment status of this person.
    * @param newHomeOwner Home ownership status of this person.
    */
   private Person(
      final FullName newName, final Address newAddress,
      final Gender newGender, final EmploymentStatus newEmployment,
      final HomeownerStatus newHomeOwner)
   {
      this.name = newName;
      this.address = newAddress;
      this.gender = newGender;
      this.employment = newEmployment;
      this.homeOwnerStatus = newHomeOwner;
   }
 
   public static Person createInstanceWithNameAndAddressOnly(
      final FullName newName, final Address newAddress)
   {
      return new Person(newName, newAddress, null, null, null);
   }
   
   public static Person createEmployedHomeOwningFemale(
      final FullName newName, final Address newAddress)
   {
      return new Person(
         newName, newAddress, Gender.FEMALE, EmploymentStatus.EMPLOYED, HomeownerStatus.HOME_OWNER);
   }

   public static Person createEmployedHomeowningMale(
      final FullName newName, final Address newAddress)
   {
      return new Person(
          newName, newAddress, Gender.MALE, EmploymentStatus.EMPLOYED, HomeownerStatus.HOME_OWNER);
   }

   public static Person createUnemployedMaleRenter(
      final FullName newName, final Address newAddress)
   {
      return new Person(
         newName, newAddress, Gender.MALE, EmploymentStatus.NOT_EMPLOYED, HomeownerStatus.RENTER);
   }

   public static Person createPersonWithFirstNameLastNameAndAddress(
      final Name newFirstName, final Name newLastName, final Address newAddress)
   {
      return new Person(
         new FullName.FullNameBuilder(newLastName, newFirstName).createFullName(),
         newAddress, null, null, null);
   }

   public static Person createPersonWithFirstNameLastNameAndAddress(
      final String newFirstName, final String newLastName, final Address newAddress)
   {
      return new Person(
         new FullName.FullNameBuilder(new Name(newLastName), new Name(newFirstName)).createFullName(),
         newAddress, null, null, null);
   }

As the above examples indicate, the clients of these methods can use very readable methods and don't need to worry too much about providing numerous parameters. The last two methods in the previous code listing are an example of combining method overloading with static initialization factory methods.

I want to focus on one additional example of a specific case in which meaningful method naming can remove the need for a parameter. It is very commonplace in Java code to have methods such as the Window.setVisible(boolean). Methods constructed in this fashion typically set something (visibility in this case) one way or the other. However, the need to pass a flag can be removed by simply writing two methods instead of one with each method clearly stating what it does. For example, Window.setVisible(boolean) could be replaced with Window.setVisible() and Window.setNotVisible() (or Window.setInvisible()). Robert Martin writes that "flag arguments are ugly" in Clean Code and warns against passing booleans to methods, which he labels "a truly terrible practice" (p. 41).

Benefits and Advantages

Using appropriately named methods that include information about expected and implied parameters in those methods' names bring some advantages over simple method/constructor overloading. Because the methods' names can be customized for what each method expects and assumes, the intent is clearer to the invoking code. As the examples above show, the methods can imply what parameters need not be explicitly provided because they are assumed as part of that method (and that intent is communicated via the methods' names rather than simply via Javadoc).

I did not focus on it explicitly here, but another advantage of carefully chosen method names over simple method overloading is the ability to include units or other context information in the method name. For example, instead of having setLength() methods that accept int and double, I could provide methods such as setWholeLengthInMeters(int) and setFractionalLengthInFeet(double).

Costs and Disadvantages

Using differently named instance methods and static initialization factory methods definitely provides some advantages over method overloading, but unfortunately still bears some of the disadvantages of method overloading from a reduction in parameters perspective. One disadvantage that differently named methods share with overloaded methods is the potential to have to write a lot of methods to support the various combinations and permutations of parameters that might be used. If a method was written only for every combination of gender, homeowner status, and employment status in the examples above, there would need to be eight methods (2 to the 3rd power). If any individual parameter can have more than 2 possibilities, then the number of different combinations of named methods just to handle the different possibilities for that one increase. Of course, parameters without finite possibilities cannot have a method written for every possible value and so will have to be passed in rather than assumed.

Although the highly descriptive method names are easy to read, the issue of having potentially many of them can reduce overall readability as the client must wade through a long list of methods when calling the class. Also, some people may not like the long method names and their taking of significant space on the screen. I personally don't mind the long names because I think the readability they provide is worth the cost of additional text on the screen. IDEs and code completion mean very few of us type these names out anymore and large and multiple monitors for developers make the issue of long method names less bothersome.

Conclusion

Methods' names can be used to communicate significant meaning to clients. In the case of our effort to clarify the parameters to be passed to a particular method (including reducing the number of parameters), naming methods appropriately can imply default settings so that parameters do not need to be provided and can explain order and other characteristics of other parameters that do need to be applied.

Tuesday, October 15, 2013

Too Many Parameters in Java Methods, Part 4: Overloading

One of the problems with expecting too many parameters to be passed to a Java method is that it is more difficult for the client of that method to be determine that they are passing the appropriate values in the appropriate order. In previous posts, I have described how custom types, parameters objects, and builders can be used to address this issue. Another way to address this issue, and the subject of this post, is to provide overloaded versions of the same method for the clients to use the one that best fits their needs. As with my earlier posts on the subject of too many method parameters, I will end this post with a brief discussion of the advantages and disadvantages of this approach.

Java supports method overloading, the ability to have different version of the same method differentiated by their method signatures. Note that a different return type as sole difference between two methods is generally not sufficient for overloading.

Method overloading might be applied for a number of reasons. One objective for overloading methods might be to support the same functionality on different types (especially if generics cannot be used to allow the method to support different types or if the methods were written before generics were available). Examples of method overloading with this intent in mind include String.valueOf(boolean), String.valueOf(char), String.valueOf(double), String.valueOf(long), String.valueOf(Object), and a few more versions of String.valueOf overloaded on a few additional types.

Another reason one might choose to overload methods is so that a client can call the appropriate version of the method for supplying just the necessary parameters. This can be done, for example, to remove the need for the client to pass in one or more nulls for parameters that don't apply or are optional. Examples of overloaded methods written to achieve this objective include the Date class constructors such as Date(int, int, int), Date(int, int, int, int, int), and Date(int, int, int, int, int, int, int).

This approach of having many overloaded versions constructors, each accepting a different number of parameters, is known as telescoping constructors and has been labeled an anti-pattern by some. In fact, the downsides of this telescoping constructors approach is one of the drivers for Josh Bloch's focus on the Builder pattern in Item #2 of the Second Edition of Effective Java. Incidentally, the Date class also provides some overloaded constructors intended to accomplish the previously mentioned objective as well, allowing Date to be constructed from a String, for example.

The idea of supplying multiple overloaded methods and constructors to accept a reduced set of required or minimally applicable parameters can be applied to our own classes. The next code listing provides the original method with far too many parameters and then shows some potential overloaded versions of that method that accept a reduced set of parameters. For purposes of this discussion, we are assuming that any parameter not provided in one of the overridden method signatures is optional or not applicable for that particular method call. The comments on the code explain how each method makes certain assumptions to reduce its parameter count.

Example of Parameter with Too Many Methods and Overloaded Versions
   /**
    * Generates and provides an instance of the Person class. This method
    * expects all characteristics of the populated Person instance and so any
    * optional or not applicable characteristics must be passed in as null.
    * 
    * @param lastName
    * @param firstName
    * @param middleName
    * @param salutation
    * @param suffix
    * @param streetAddress
    * @param city
    * @param state
    * @param isFemale
    * @param isEmployed
    * @param isHomeOwner
    * @return A Person object.
    */
   public Person createPerson(
      final String lastName,
      final String firstName,
      final String middleName,
      final String salutation,
      final String suffix,
      final String streetAddress,
      final String city,
      final String state,
      final boolean isFemale,
      final boolean isEmployed,
      final boolean isHomeOwner)
   {
      // implementation goes here...
   }

   /**
    * Generate and provide an instance of the Person class that has only a first
    * and last name and address information. This method does not make any
    * assumptions about other characteristics of the instantiated Person, but
    * simply leaves those attributes undefined.
    * 
    * @param lastName
    * @param firstName
    * @param streetAddress
    * @param city
    * @param state
    * @return Instance of Person class with no middle name and without specified
    *    gender, employment status, or home ownership status.
    */
   public Person createPerson(
      final String lastName,
      final String firstName,
      final String streetAddress,
      final String city,
      final String state)
   {
      // implementation goes here...
   }

   /**
    * Generate and provide instance of Person class with no middle name and
    * with specified home ownership status. All instances of Person returned
    * from this method are assumed to be Female and to be Employed, but have no
    * address information.
    * 
    * @param lastName
    * @param firstName
    * @param homeOwnerStatus
    * @return Instance of Person with provided first name, provided last name,
    *    and provided home ownership status, and assumed to be an employed
    *    female.
    */
   public Person createPerson(
      final String lastName,
      final String firstName,
      final boolean homeOwnerStatus)
   {
      // implementation goes here...
   }

The overloaded methods' Javadoc descriptions tell a little about their differing approach. The first method expected all characteristics of the Person instance to be provided and null would need to be provided for parameters that are not applicable (such as if a person does not have a middle name or that middle name is not important for the use in this case). The second overloaded version did not expect all the parameters to be provided and assumed that the parameters it did not expect would remain undefined in the returned Person instance.

The third overloaded method version mostly made assumptions about the characteristics for which it did not provide an explicit parameter. For example, it assumed that the instantiated Person is both female and employed. There is no way with that third approach to instantiate a person who is either male or unemployed. This illustrates a weakness of dealing with too many parameters with simple method overloading (overloading methods with same name based only on number and types of parameters).

I have not shown any constructors of my own in this post, but the same issues and approaches apply as shown for the non-constructor methods above. Likewise, overloaded constructors share the same advantages and disadvantages as overloaded non-constructor methods.

Benefits and Advantages

Method overloading in Java seems easy to understand and is common in several languages including C/C++ and C#. Method overloading is particularly effective when parameters are optional. For example, method overloading that removed the expectation of a middle name being passed in was far more effective in my examples than the method overloading making assumptions about a specific instantiation being an employed female. If the characteristics of middle name, gender, and employment status are all truly optional, then not assuming a value for any of them at all seems better than assuming a specific value for them.

Costs and Disadvantages

Judicious method overloading can be useful, but method overloading must be used carefully. The Defining Methods section of the Classes and Objects lesson of the Learning the Java Language trail warns: "Overloaded methods should be used sparingly, as they can make code much less readable."

Even my simple three examples showed how overloading can quickly become difficult to read. In my examples, the reader or user of this code would either need to read the Javadoc carefully and trust it to be current and accurate or would need to delve into the implementation to see what each overloaded version of the method did. In an IDE, especially if there are numerous overloaded versions of the same method, it can be difficult to see which one applies in a given situation.

My example showed that comments must be used to explain assumptions made by the overloaded methods. As just mentioned, these could be out of date or inaccurate or not even available if the developer did not bother to write them. It would obviously be better to be able to name the methods differently so that the name of the method could give clues about its assumptions rather than relying solely on Javadoc. Using named methods in this way will be the subject of a later post, but using different names for the methods by definition makes them no longer overloaded methods.

My examples showed a particular limitation of using overloaded (same named) methods with multiple parameters of the same type. The third example accepts a single boolean, but only the Javadoc and the name of that parameter could tell me that it applied to home ownership and not to gender or employment status. I cannot provide similar overloaded methods to take the same name information and a boolean indicating something different (such as gender or employment status) because that method would have the same signature as the method where the boolean indicated home ownership status. This again could be remedied through the use of differently named methods that indicated for which boolean condition they applied.

Another way to address this last mentioned limitation would be to use custom types and/or parameters objects and provide various versions of overloaded methods accepting different combinations of those custom types. This is shown with custom types in the next code listing which shows how the method accepting two name Strings can be overloaded by a single third parameter for all three cases when those three cases don't each need to share the same type.

Custom Types Enable Improved Method/Constructor Overloading
   public Person createPerson(
      final String lastName,
      final String firstName,
      final HomeownerStatus homeOwnership)
   {
      // implementation goes here...
   }

   public Person createPerson(
      final String lastName,
      final String firstName,
      final Gender gender)
   {
      // implementation goes here...
   }

   public Person createPerson(
      final String lastName,
      final String firstName,
      final EmploymentStatus employmentStatus)
   {
      // implementation goes here...
   }

One final disadvantage I want to mention related to using method overloading to address the problems associated with too many parameters to a method or constructor is that such an approach can lead to significant maintenance work in the future. Any time an attribute to that class (constructors) or a parameter to a method is added or removed or even changed, multiple constructors and/or methods may need to be individually reviewed and potentially changed.

Conclusion

Overloaded methods do have their place and can be a convenient way to provide more understandable and readable methods and constructors for clients. However, I find this approach to be the "best" approach less often than some of the other approaches already covered (custom types, parameters objects, builders) and even less often than some of the approaches I intend to cover (such as differently and explicitly named versions of the same methods and constructors). Some of the limitations and disadvantages of the method overloading approach can be reduced through the use the method overloading in conjunction with some of these other approaches. For example, the use of custom types and parameters objects can significantly improve one's ability to more narrowly tailor the various versions of an overloaded method or constructor to what is desired.

Saturday, October 12, 2013

Too Many Parameters in Java Methods, Part 3: Builder Pattern

In my two immediately previous posts, I looked at reducing the number of parameters required for a constructor or method invocation via custom types and parameter objects. In this post, I look at use of the builder pattern to reduce the number of parameters required for a constructor with some discussion on how this pattern can even help with non-constructor methods that take too many parameters.

In the Second Edition of Effective Java, Josh Bloch introduces use of the builder pattern in Item #2 for dealing with constructors that require too many parameters. Bloch not only demonstrates how to use the Builder, but explains it advantages over constructors accepting a large number of parameters. I will get to those advantages at the end of this post, but think it's important to point out that Bloch has devoted an entire item in his book to this practice.

To illustrate the advantages of this approach, I'll use the following example Person class. It doesn't have all the methods I would typically add to such a class because I want to focus on its construction.

Person.java (without Builder Pattern)
package dustin.examples;

/**
 * Person class used as part of too many parameters demonstration.
 * 
 * @author Dustin
 */
public class Person
{
   private final String lastName;
   private final String firstName;
   private final String middleName;
   private final String salutation;
   private final String suffix;
   private final String streetAddress;
   private final String city;
   private final String state;
   private final boolean isFemale;
   private final boolean isEmployed;
   private final boolean isHomewOwner;

   public Person(
      final String newLastName,
      final String newFirstName,
      final String newMiddleName,
      final String newSalutation,
      final String newSuffix,
      final String newStreetAddress,
      final String newCity,
      final String newState,
      final boolean newIsFemale,
      final boolean newIsEmployed,
      final boolean newIsHomeOwner)
   {
      this.lastName = newLastName;
      this.firstName = newFirstName;
      this.middleName = newMiddleName;
      this.salutation = newSalutation;
      this.suffix = newSuffix;
      this.streetAddress = newStreetAddress;
      this.city = newCity;
      this.state = newState;
      this.isFemale = newIsFemale;
      this.isEmployed = newIsEmployed;
      this.isHomewOwner = newIsHomeOwner;
   }
}

This class's constructor works, but it is difficult for client code to use properly. The Builder pattern can be used to make the constructor easier to use. NetBeans will refactor this for me as I have written about previously. An example of the refactored code is shown next (NetBeans does this by creating all new Builder class).

PersonBuilder.java
package dustin.examples;


public class PersonBuilder
{
   private String newLastName;
   private String newFirstName;
   private String newMiddleName;
   private String newSalutation;
   private String newSuffix;
   private String newStreetAddress;
   private String newCity;
   private String newState;
   private boolean newIsFemale;
   private boolean newIsEmployed;
   private boolean newIsHomeOwner;

   public PersonBuilder()
   {
   }

   public PersonBuilder setNewLastName(String newLastName) {
      this.newLastName = newLastName;
      return this;
   }

   public PersonBuilder setNewFirstName(String newFirstName) {
      this.newFirstName = newFirstName;
      return this;
   }

   public PersonBuilder setNewMiddleName(String newMiddleName) {
      this.newMiddleName = newMiddleName;
      return this;
   }

   public PersonBuilder setNewSalutation(String newSalutation) {
      this.newSalutation = newSalutation;
      return this;
   }

   public PersonBuilder setNewSuffix(String newSuffix) {
      this.newSuffix = newSuffix;
      return this;
   }

   public PersonBuilder setNewStreetAddress(String newStreetAddress) {
      this.newStreetAddress = newStreetAddress;
      return this;
   }

   public PersonBuilder setNewCity(String newCity) {
      this.newCity = newCity;
      return this;
   }

   public PersonBuilder setNewState(String newState) {
      this.newState = newState;
      return this;
   }

   public PersonBuilder setNewIsFemale(boolean newIsFemale) {
      this.newIsFemale = newIsFemale;
      return this;
   }

   public PersonBuilder setNewIsEmployed(boolean newIsEmployed) {
      this.newIsEmployed = newIsEmployed;
      return this;
   }

   public PersonBuilder setNewIsHomeOwner(boolean newIsHomeOwner) {
      this.newIsHomeOwner = newIsHomeOwner;
      return this;
   }

   public Person createPerson() {
      return new Person(newLastName, newFirstName, newMiddleName, newSalutation, newSuffix, newStreetAddress, newCity, newState, newIsFemale, newIsEmployed, newIsHomeOwner);
   }
   
}

I prefer to have my Builder as a nested class inside the class whose object it builds, but the NetBeans automatic generation of a standalone Builder is very easy to use. Another difference between the NetBeans-generated Builder and the Builders I like to write is that my preferred Builder implementations have required fields provided in the Builder's constructor rather than provide a no-arguments constructor. The next code listing shows my Person class from above with a Builder added into it as a nested class.

Person.java with Nested Person.Builder
package dustin.examples;

/**
 * Person class used as part of too many parameters demonstration.
 * 
 * @author Dustin
 */
public class Person
{
   private final String lastName;
   private final String firstName;
   private final String middleName;
   private final String salutation;
   private final String suffix;
   private final String streetAddress;
   private final String city;
   private final String state;
   private final boolean isFemale;
   private final boolean isEmployed;
   private final boolean isHomewOwner;

   public Person(
      final String newLastName,
      final String newFirstName,
      final String newMiddleName,
      final String newSalutation,
      final String newSuffix,
      final String newStreetAddress,
      final String newCity,
      final String newState,
      final boolean newIsFemale,
      final boolean newIsEmployed,
      final boolean newIsHomeOwner)
   {
      this.lastName = newLastName;
      this.firstName = newFirstName;
      this.middleName = newMiddleName;
      this.salutation = newSalutation;
      this.suffix = newSuffix;
      this.streetAddress = newStreetAddress;
      this.city = newCity;
      this.state = newState;
      this.isFemale = newIsFemale;
      this.isEmployed = newIsEmployed;
      this.isHomewOwner = newIsHomeOwner;
   }

   public static class PersonBuilder
   {
      private String nestedLastName;
      private String nestedFirstName;
      private String nestedMiddleName;
      private String nestedSalutation;
      private String nestedSuffix;
      private String nestedStreetAddress;
      private String nestedCity;
      private String nestedState;
      private boolean nestedIsFemale;
      private boolean nestedIsEmployed;
      private boolean nestedIsHomeOwner;

      public PersonBuilder(
         final String newFirstName,
         final String newCity,
         final String newState) 
      {
         this.nestedFirstName = newFirstName;
         this.nestedCity = newCity;
         this.nestedState = newState;
      }

      public PersonBuilder lastName(String newLastName)
      {
         this.nestedLastName = newLastName;
         return this;
      }

      public PersonBuilder firstName(String newFirstName)
      {
         this.nestedFirstName = newFirstName;
         return this;
      }

      public PersonBuilder middleName(String newMiddleName)
      {
         this.nestedMiddleName = newMiddleName;
         return this;
      }

      public PersonBuilder salutation(String newSalutation)
      {
         this.nestedSalutation = newSalutation;
         return this;
      }

      public PersonBuilder suffix(String newSuffix)
      {
         this.nestedSuffix = newSuffix;
         return this;
      }

      public PersonBuilder streetAddress(String newStreetAddress)
      {
         this.nestedStreetAddress = newStreetAddress;
         return this;
      }

      public PersonBuilder city(String newCity)
      {
         this.nestedCity = newCity;
         return this;
      }

      public PersonBuilder state(String newState)
      {
         this.nestedState = newState;
         return this;
      }

      public PersonBuilder isFemale(boolean newIsFemale)
      {
         this.nestedIsFemale = newIsFemale;
         return this;
      }

      public PersonBuilder isEmployed(boolean newIsEmployed)
      {
         this.nestedIsEmployed = newIsEmployed;
         return this;
      }

      public PersonBuilder isHomeOwner(boolean newIsHomeOwner)
      {
         this.nestedIsHomeOwner = newIsHomeOwner;
         return this;
      }

      public Person createPerson()
      {
         return new Person(
            nestedLastName, nestedFirstName, nestedMiddleName,
            nestedSalutation, nestedSuffix,
            nestedStreetAddress, nestedCity, nestedState,
            nestedIsFemale, nestedIsEmployed, nestedIsHomeOwner);
      }
   }
}

The Builder can be even nicer when enhanced through use of custom types and parameters objects as outlined in my first two posts on the "too many parameters" problem. This is shown in the next code listing.

Person.java with Nested Builder, Custom Types, and Parameters Object
package dustin.examples;

/**
 * Person class used as part of too many parameters demonstration.
 * 
 * @author Dustin
 */
public class Person
{
   private final FullName name;
   private final Address address;
   private final Gender gender;
   private final EmploymentStatus employment;
   private final HomeownerStatus homeOwnerStatus;

   /**
    * Parameterized constructor can be private because only my internal builder
    * needs to call me to provide an instance to clients.
    * 
    * @param newName Name of this person.
    * @param newAddress Address of this person.
    * @param newGender Gender of this person.
    * @param newEmployment Employment status of this person.
    * @param newHomeOwner Home ownership status of this person.
    */
   private Person(
      final FullName newName, final Address newAddress,
      final Gender newGender, final EmploymentStatus newEmployment,
      final HomeownerStatus newHomeOwner)
   {
      this.name = newName;
      this.address = newAddress;
      this.gender = newGender;
      this.employment = newEmployment;
      this.homeOwnerStatus = newHomeOwner;
   }

   public FullName getName()
   {
      return this.name;
   }

   public Address getAddress()
   {
      return this.address;
   }

   public Gender getGender()
   {
      return this.gender;
   }

   public EmploymentStatus getEmployment()
   {
      return this.employment;
   }

   public HomeownerStatus getHomeOwnerStatus()
   {
      return this.homeOwnerStatus;
   }

   /**
    * Builder class as outlined in the Second Edition of Joshua Bloch's
    * Effective Java that is used to build a {@link Person} instance.
    */
   public static class PersonBuilder
   {
      private FullName nestedName;
      private Address nestedAddress;
      private Gender nestedGender;
      private EmploymentStatus nestedEmploymentStatus;
      private HomeownerStatus nestedHomeOwnerStatus;

      public PersonBuilder(
         final FullName newFullName,
         final Address newAddress) 
      {
         this.nestedName = newFullName;
         this.nestedAddress = newAddress;
      }

      public PersonBuilder name(final FullName newName)
      {
         this.nestedName = newName;
         return this;
      }

      public PersonBuilder address(final Address newAddress)
      {
         this.nestedAddress = newAddress;
         return this;
      }

      public PersonBuilder gender(final Gender newGender)
      {
         this.nestedGender = newGender;
         return this;
      }

      public PersonBuilder employment(final EmploymentStatus newEmploymentStatus)
      {
         this.nestedEmploymentStatus = newEmploymentStatus;
         return this;
      }

      public PersonBuilder homeOwner(final HomeownerStatus newHomeOwnerStatus)
      {
         this.nestedHomeOwnerStatus = newHomeOwnerStatus;
         return this;
      }

      public Person createPerson()
      {
         return new Person(
            nestedName, nestedAddress, nestedGender,
            nestedEmploymentStatus, nestedHomeOwnerStatus);
      }
   }
}

The last couple of code listings show how a Builder is typically used - to construct an object. Indeed, the item on the builder (Item #2) in Joshua Bloch's Second Edition of Effective Java is in the chapter on creating (and destroying) object. However, the builder can help indirectly with non-constructor methods by allowing an easier way to build parameters objects that are passed to methods.

For example, in the last code listing, the methods have some parameters objects (FullName and Address) passed to them. It can be tedious for clients to have to construct these parameters objects and the builder can be used to make that process less tedious. So, although the builder is used for construction in each case, it indirectly benefits non-constructor methods by allowing for easier use of the parameters objects that reduce a method's argument count.

The new definitions of the FullName and Address classes to be used as parameters objects and using the Builder themselves are shown next.

FullName.java with Builder
package dustin.examples;

/**
 * Full name of a person.
 * 
 * @author Dustin
 */
public final class FullName
{
   private final Name lastName;
   private final Name firstName;
   private final Name middleName;
   private final Salutation salutation;
   private final Suffix suffix;

   private FullName(
      final Name newLastName,
      final Name newFirstName,
      final Name newMiddleName,
      final Salutation newSalutation,
      final Suffix newSuffix)
   {
      this.lastName = newLastName;
      this.firstName = newFirstName;
      this.middleName = newMiddleName;
      this.salutation = newSalutation;
      this.suffix = newSuffix;
   }

   public Name getLastName()
   {
      return this.lastName;
   }

   public Name getFirstName()
   {
      return this.firstName;
   }

   public Name getMiddleName()
   {
      return this.middleName;
   }

   public Salutation getSalutation()
   {
      return this.salutation;
   }

   public Suffix getSuffix()
   {
      return this.suffix;
   }

   @Override
   public String toString()
   {
      return  this.salutation + " " + this.firstName + " " + this.middleName
            + this.lastName + ", " + this.suffix;
   }

   public static class FullNameBuilder
   {
      private final Name nestedLastName;
      private final Name nestedFirstName;
      private Name nestedMiddleName;
      private Salutation nestedSalutation;
      private Suffix nestedSuffix;

      public FullNameBuilder(
         final Name newLastName, final Name newFirstName)
      {
         this.nestedLastName = newLastName;
         this.nestedFirstName = newFirstName;
      }

      public FullNameBuilder middleName(final Name newMiddleName)
      {
         this.nestedMiddleName = newMiddleName;
         return this;
      }

      public FullNameBuilder salutation(final Salutation newSalutation)
      {
         this.nestedSalutation = newSalutation;
         return this;
      }

      public FullNameBuilder suffix(final Suffix newSuffix)
      {
         this.nestedSuffix = newSuffix;
         return this;
      }

      public FullName createFullName()
      {
         return new FullName(
            nestedLastName, nestedFirstName, nestedMiddleName,
            nestedSalutation, nestedSuffix);
      }
   }
}
Address.java with Builder
package dustin.examples;

/**
 * Representation of a United States address.
 * 
 * @author Dustin
 */
public final class Address
{
   private final StreetAddress streetAddress;
   private final City city;
   private final State state;

   private Address(final StreetAddress newStreetAddress, final City newCity, final State newState)
   {
      this.streetAddress = newStreetAddress;
      this.city = newCity;
      this.state = newState;
   }

   public StreetAddress getStreetAddress()
   {
      return this.streetAddress;
   }

   public City getCity()
   {
      return this.city;
   }

   public State getState()
   {
      return this.state;
   }

   @Override
   public String toString()
   {
      return this.streetAddress + ", " + this.city + ", " + this.state;
   }
   
   public static class AddressBuilder
   {
      private StreetAddress nestedStreetAddress;
      private final City nestedCity;
      private final State nestedState;

      public AddressBuilder(final City newCity, final State newState)
      {
         this.nestedCity = newCity;
         this.nestedState = newState;
      }

      public AddressBuilder streetAddress(final StreetAddress newStreetAddress)
      {
         this.nestedStreetAddress = newStreetAddress;
         return this;
      }

      public Address createAddress()
      {
         return new Address(nestedStreetAddress, nestedCity, nestedState);
      }
   }
}

With the above builders included in the classes, a Person instance can be created as shown in the next code listing. A more traditional instantiation of a Person instance is shown after that for comparison.

Two Examples of Client Code Instantiating a Person with Builders
final Person person1 = new Person.PersonBuilder(
   new FullName.FullNameBuilder(
      new Name("Dynamite"), new Name("Napoleon")).createFullName(),
   new Address.AddressBuilder(
      new City("Preston"), State.ID).createAddress()).createPerson();

final Person person2 = new Person.PersonBuilder(
   new FullName.FullNameBuilder(
      new Name("Coltrane"), new Name("Rosco")).middleName(new Name("Purvis")).createFullName(),
   new Address.AddressBuilder(
      new City("Hazzard"), State.GA).createAddress())
      .gender(Gender.MALE).employment(EmploymentStatus.EMPLOYED).createPerson();
Instantiating a Person Without a Builder
final person = new Person("Coltrane", "Rosco", "Purvis", null, "Hazzard", "Georgia", false, true, true);

As the previous code snippets show, the client code for calling a traditional Java constructor is far less readable and far easier to mess up than use of the builder classes. The variety of the same types (strings and booleans) and the necessity to place nulls in the constructor call for optional attributes make provide many ways for this approach to end badly.

Benefits and Advantages

There is a considerable cost to the Builder pattern in that one must essentially double the number of lines of code each attribute and for setting those attributes. This price pays off, however, when the client code benefits greatly in terms of usability and readability. The parameters to the constructor are reduced and are provided in highly readable method calls.

Another advantage of the Builder approach is the ability to acquire an object in a single statement and state without the object in multiple states problem presented by using "set" methods. I am increasingly appreciating the value of immutability in a multi-core world and the Builder pattern is perfectly suited for an immutable class when that class features a large number of attributes. I also like that there is no need to pass in null for optional parameters to the constructor.

The Builder pattern not only makes the code more readable, but makes it even easier to apply an IDE's code completion feature. Further benefits of the Builder pattern when used with constructors are outlined in Item #2 of the Second Edition of Effective Java.

Costs and Disadvantages

As shown and mentioned above, the number of lines of code of a given class must be essentially doubled for "set" methods with the builder approach. Furthermore, although client code is more readable, the client code is also more verbose. I consider the benefit of greater readability worth the cost as the number of arguments increase or as more arguments share the same type or as the number of optional arguments increase.

More lines of code in the class with the builder sometimes mean that developers may forget to add support for a new attribute to the builder when they add that attribute to the main class. To try to help with this, I like to nest my builders inside the class that they build so that it's more obvious to the developer that there is a relevant builder that needs to be similarly updated. Although there is still risk of the developer forgetting to add support for a new attribute to the builder, this is really no different than the risk of forgetting to add a new attribute to a class's toString(), equals(Object), hashCode() or other methods often based on all attributes of a class.

In my implementation of the Builder, I made the client pass required attributes into the builder's constructor rather than via "set" methods. The advantage of this is that the object is always instantiated in a "complete" state rather than sitting in an incomplete state until the developer calls (if ever calls) the appropriate "set" method to set additional fields. This is necessary to enjoy the benefits of immutability. However, a minor disadvantage of that approach is that I don't get the readability advantages of methods named for the field I am setting.

The Builder, as its name suggests, is really only an alternative to constructors and not directly used to reduce the number of non-constructor method parameters. However, the builder can be used in conjunction with parameters objects to reduce the number of non-constructor method arguments. Further arguments against use of the Builder for object construction can be found in a comment on the A dive into the Builder pattern post.

Conclusion

I really like the Builder pattern for constructing objects when I have a lot of parameters, especially if many of these parameters are null and when many of them share the same data type. A developer might feel that the extra code to implement a Builder might not justify its benefits for a small number of parameters, especially if the few parameters are required and of different types. In such cases, it might be considered desirable to use traditional constructors or, if immutability is not desired, use a no-argument constructor and require the client to know to call the necessary "set" methods.