Autocompleting a lot of parameters

Autocompleting a lot of parameters

Some methods have many parameters. Sometimes they start out like that, sometimes they grow like that over time. Even though a maximum of two parameters is preferable, configuration for a method that does a big thing is difficult. Take curl for example; curl has a lot of options and so several wrappers around curl have arisen to deal with configuring it in a more humane manner. How can we keep the clutter of many parameters as low as possible, while maintaining autocompletion?

A good example for us at Procurios: Finding out on which node (a page in a site) a certain functionality, a so called Snippet is mounted:

  • Which Snippet?
  • Which site?
  • Is the node published or not?
  • Is the user allowed to see the node?
  • Does the functionality have a certain configuration option?

The 'shopping cart quick view' snippet, for example should link to the actual 'shopping cart' snippet. It should be on the same site and it should use the same webshop.

Let's assume we have an API for dealing with Snippets. You could imagine a method like this:

function findNodesForSnippet(
$snippetClassName,
$site = null,
$published = null,
$visible = null,
array $configOptions = array())
{
// snip...
} $snippets = findNodesForSnippet(
ShoppingCartSnippet::class,
$currentSite,
null,
null,
array('webshopId' => $webshopId)
);

This is not a very readable approach. And what if even more possible constraints show up? We would add them to the end and create even more clutter. Clearly, almost any alternative would be preferable.

A common pattern is to use arrays. By using arrays, the number of parameter could be endless, or zero. It doesn't matter; there is exactly as much clutter as you need:

function findNodesForSnippet(
$snippetClassName,
array $parameters = array())
{
// snip...
} $snippets = findNodesForSnippets(
ShoppingCartSnippet::class,
array(
'site' => $currentSite, 
'configOptions' => array(
'webshopId' => $webshopId
)
));

This is already much cleaner, but it has a severe drawback: lack of autocompletion, which in turn is a symptom of stringly typedness. A partial solution would be to use constants as keys for the configuration array, but still the programmer would need to know to look for them. The code is not transparent to the programmer.

We have a better way! By using smart worker objects we can have our autocompletion, while maintaining the least amount of clutter. All the smart object needs is a fluent interface. That means that every setter should return $this, the object itself, so that consecutive methods can be chained as part of the same statement. Like this:

$snippets = $SnippetApi->findNodesForSnippets(
ShoppingCartSnippet::class)
->inSites(array($currentSite))
->withOption('webshopId', $webshopId)
->please();

The findNodesForSnippet method has only one parameter and returns an object of type SnippetLookup, which gets all the dependencies it needs via the constructor. It only does its work when politely instructed to do so. Until then, you can add more configuration to it, or change the existing options if need be. You can even pass it around to allow other parts of your code to modify it.

By using fluent interfaces and as strong as possible typing, we help our editor of choice (<3 PhpStorm) help us, and make our codebase a nicer place to be.

Leave a comment...

Leave a comment

Italic en bold

*Dit is italic*, en _dit ook_.
**Dit is bold**, en __dit ook__.

Links

Dit is een link naar [Procurios](http://www.procurios.nl).

Lijsten

Een lijst met bullets kan worden gemaakt met:
- Min-tekens,
+ Plus-tekens,
* Of een asterisk.

Een genummerde lijst kan worden gemaakt met:
1. Lijst-item nummer 1.
2. Lijst-item nummer 2.

Quote

Onderstaande tekst vormt een quote:
> Dit is de eerste regel.
> Dit is de tweede regel.

Code

Er kan een blok met code worden geplaatst. Door voor de tekst vier spaties te plaatsen, ontstaat een code-block.