07/13, @2:33pm: Singular or plural: a naming dilemna that reveals some design defects
Working on the new Limonade 0.4 branch, it’s also time to read and read again current code, and checking code design consistency.
Something i didn’t notice before suddenly appears: options are managed with the singular function option but params are retrieved with the plural option params… very confusing…
I probably had in mind those two naming ways:
- using plural, like accessing a member of an array
- using singular, like an action method or like saying “get/set option”
I’ll try in this post to explain each feature in order to find the right naming. As me, you’ll probably be surprised how such a small question raises new problematics and reveals hidden design defects.
About function naming
Every code project has its conventions. Habits also depends on the language. But there are common rules that you can find most of the time.
In Limonade, i choosed to be as close as possible to the PHP native API conventions:
- lowercase
- underscored names
- prefixed by module name (but i’ve not prefixed all my functions with
limonade_… too verbosed…)
I’m trying to keep functions names short and simple but always meaningful. For simplicty and compacity, some function are in the same time a getter and a setter: so i don’t need to, and i can’t, use a get_ or set_ prefix. But remember those functions are still verbs.
Options features
Many features are covered in this single option() function
- getting all options (no argument provided)
- getting an option (one argument provided)
- setting an option (two arguments provided)
I should have wrote option with three function instead of one:
get_all_options()get_option($name)set_option($name, $value)
This all-in-one getter/setter function is very convenient but it’s also the source of our problem.
I’m not sure that getting all options is useful: perhaps for internal use ? There’s no need of it for now, so i should remove it in the next release (never implement unnecessary features…).
So, we only use it for getting and setting an option: prefering a singular naming is probably the most common and logical solution.
Params features
Actually, params() does 4 things:
- getting all params (no argument provided)
- getting a param (by providing a argument)
- setting a param (by providing a $name argument and a $value argument, or n arguments…)
- resetting params (with a null argument)
Getting a param is the main use. Maybe getting all can be useful too. But setting and resetting should really be reserved for an internal use. Params should be read-only: they are passed by current uri, so they can’t be changed.
Maybe you might want to filter a param in the before function, like in Wikir
function before()
{
if($page_name = params('page'))
{
params('page', rawurldecode($page_name));
}
}
In this case, if params() has no writing feature anymore, we need to use a global variable or better, creating our own filter function and calling it when needed
function my_filtered_params()
{
$params = params();
if(array_key_exists('page', $params)) $params['page'] = rawurldecode($page_name);
return $params;
}
And about the reset feature, there is no reason to use it unless for internal use: this is a good example to show that using public API in a private context makes it more complicated that it needs to be.
So we only need to get all params or one. 95% of the time, we’ll call a unique param: so it will be singular
And next… refactoring
Now I really need to refactor those functions. I will also apply the same process to all functions of the limonade public API to improve it.
I read recently this great article by Yehuda Katz. Heaven if we can’t compare with such a huge task (Rails 3.0 refactoring), i note 4 refactoring good practices:
- Having a test suite for each part that will be refactored
- Don’t add any new features during a refactoring cycle
- Make changes step by step, by logical groups and make tests after each change
- Separate public api from internal functions / don’t use public api functions for internal use.
So Limonade will need a good refactoring phase: not for 0.4 branch because it adds new features, maybe in the 0.5 branch after completing unit testing.
(Author: Fabrice Luraine - second reading/corrections: Mathias Standaert)