Some thoughts on constructor and method parameters
I consider a best practice to keep to the minimum the number of arguments a method accepts. As uncle Bob explains in his “Clean code” book we should always favour niladic (no arguments), monadic (1 argument) or dyadic (2 argument) methods and avoid whenever possible methods with more than 3 arguments, if not possible we should be able to clearly justify them.
The higher number of arguments a method accepts the harder it’ll be to read, understand and test.
When a method needs too much arguments, it is normally a sign of:
- Poor encapsulation
- The method is doing more than one thing, breaking the Single Responsibility principle. The arguments define what the method will do, they define and change the method execution path. (i.e. flag methods)
- Method signatures are harder to read and it’s easier to introduce errors by swapping the order of parameters (specially if they are of the same type). (link to FB issue to highlight parameters. i.e. assertEquals();)
- Method parameters are all part of the same concept and could be encapsulated in an object with its own type.
- Arguments belong to different levels of abstraction and are harder to understand.
To reduce the number of arguments in class methods you can consider different techniques depending on what the exact problem is in each case:
- Create specialised objects that wrap several parameters. i.e. x, y could be a Point instance.
- Transform method arguments into class properties so that they don’t need to be passed between methods.
- Create different methods or strategies to fork the behaviour instead of using flag parameters
- Use factory methods and builders.
All points above can even get worse when overusing optional parameters, which lot of people use to alleviate the lack of method and constructor overloading in ActionScript3 instead of using Builders, Factories of creating different named methods.
If we focus on constructors I think they should only accept:
- Required parameters for the object to be properly initialised.
- Optional invariant parameters. Parameters that can’t be changed during the life of the object and that thus need to be specified during born.
Let’s consider the typical Person object with a name, surname, age and a unique invariant Id. We define a constructor with 1 required argument and 3 optional ones:
private var _id : int;
public var name : String;
public var surname : String
public var street : String;
public function Person( id : int, name : String = "", surname:String = "", streetString="") {
this._id = id;
this.name = name;
this.surname = surname;
this.street = street;
}
public function get id() : int {
return _id;
}
}
You could create different instances like:
var p2 : Person = new Person( 2, "John", null, "address2");
var p3 : Person = new Person( 3, "Andy", "address3");
var p4 : Person = new Person( 4, null, "addres4", "Martin");
The code above will compile fine, the compiler won’t complain at all since all declarations are right, but there’re several data integrity errors here, errors that are normally very hard to find and isolate. i.e. p3 is setting the address as the surname. p4 is swapping the surname and the address.
In this case, the Person type and the data might be self explanatory, but there are a bunch of other cases that are not. Having cluttered constructors with lots of optional parameters is quite common when dealing with Custom Events.
What would be interesting is to be able to pass the optional parameters in a named way, removing the order constraint while making the solution more readable, developer friendly and robust to changes:
var p2 : Person = new PersonBuilder( 2 ).name( 'John').address('address2').build();
var p3 : Person = new PersonBuilder( 3 ).name( 'Andy').address('address3').build();
var p4 : Person = new PersonBuilder( 4 ).address('address4').surname('Martin').build();
This solution is a kind of Buider pattern implemented in a fluent way, a train wreck. It’s also somehow mimicking named parameters in other languages. The nice things I really like about this syntax is:
- It’s a compact expression. It can be written in just one line.
- The order of the optional parameters is not important anymore.
- It’s easy to read and prevents parameter swapping. In some cases it can also be read as a natural language phrase.
- In case of invariant optional parameters the builder can hide the implementation in the build method.
- It doesn’t break Demeter’s law. Although implemented as a train wreck, each method is applied on the same object.
As mentioned above a common scenario where you could apply this technique is when dealing with custom events. Imagine you want to implement CRUD operations in terms of Persons. You could have:
PersonEvent.removePersonEvent( 2 ).cancelable( true ).build();
PersonEvent.updatePersonEvent( 2 ).surname( 'Smith' ).build();
PersonEvent.getPersonEvent( 100 ).build();
PersonEvent.getPeopleListEvent( ).pageOffset( 10 ).numResults( 50 ).build();
PersonEvent.getPeopleListEvent( ).pageOffset( 10 ).numResults( 50 ).name('Xavi*').build();
This implementation would allow you to reuse the same PersonEvent for the different operations without cluttering the constructor with all the different permutations of optional and required parameters in a scalable way. Another option in this case would be using static factory methods (but this won’t solve the optional parameters mess).
4 Comments to “Some thoughts on constructor and method parameters”
Leave a Reply

Hi Xavi
I like the fluent builder interface very much. However to be able to differentiate setters/getters from builder methods i tend to use the prefix with, eg. userObjectFactory.withName(“Xavi”).build();
Best,
Ralf.
Hacer setters que te devuelven el propio objeto que los contiene. Es precioso! y como dices, limpias los parámetros y es muy fácil de integrar.
Gracias
[...] Source http://www.rialvalue.com/blog/2010/03/30/some-thoughts-on-method-parameters/ [...]
can u give an example code for a builder for the person class? (parameters in a named way)