Mi compañera y manager en Holaluz Mavi Jiménez va a hacer un dibujo cada día del mes sobre una palabra propuesta en twitter. Y aquí vamos a intentar escribir un post por cada una de ellas.
Parameter
¿Cuántos parámetros debería tener la signatura de una función? Es una pregunta interesante porque una cosa es eso y otra la cantidad que realmente necesita. Puede que una función o método necesite veinte parámetros, pero creo que estaremos de acuerdo en que ese número es impracticable.
Así que tenemos que resolver un par de problemas:
- Cuántos parámetros como máximo consideramos aceptables on una función para que tenga una signatura manejable.
- Cómo salvamos la distancia entre una signatura manejable y proporcionar todos los parámetros necesarios.
El mágico número siete
Ya he traído a colación anteriormente este artículo de George A. Miller, fundamental en la psicología cognitiva. En resumen, se trata de la idea de que nuestra memoria a corto plazo o memoria de trabajo tiene una capacidad limitada para mantener unidades de información simultáneamente mientras realizamos una tarea. Este límite rondaría los siete chunks o elementos de información. Actualmente no se intenta determinar un valor preciso de esta capacidad, ya que varía según diversas circunstancias, pero la idea de base de que es una capacidad limitada nos ayuda a explicar, en primer lugar, porque una signatura de una función con muchos parámetros dificulta nuestra comprensión.
También nos sirve para realizar una estimación, nada científica por otra parte, de la cantidad de parámetros máxima que debería tener un método o función. Repito, esto que voy a hacer no es científico, pero a lo mejor es útil.
Partimos del número siete, pero necesitaremos uno o dos chunks para llevar cuenta de qué estamos haciendo y no olvidarnos por el camino. Esto nos deja unos cinco chunks libres.
Gastamos otros dos en el nombre del método o función y en saber qué es lo que hace. ¿Me sigues? Nos quedan tres chunks libres, cuatro con suerte.
Conclusión: tres parámetros es el máximo recomendable para trabajar cómodamente, manteniendo la carga cognitiva bajo control.
Soluciones para limitar el número de parámetros
Value Objects. Se trata de ver si algunos de esos parámetros se agrupan en una unidad conceptual que puede sernos útil no solo en esa llamada, sino como concepto del dominio. Por ejemplo, si tenemos que pasar una cantidad que representa dinero y la unidad monetaria, es que en realidad necesitamos un VO Money.
public function setPrice(float $priceAmount, string $priceMonetaryUnit);
//...
public function setPrice(Money $price)
Parameter Object. Si aun así nos quedan muchos parámetros, podemos crear un objeto que los agrupe todos bajo un nombre significativo. Es posible, incluso, que lo puedas reutilizar.
public function setContactData($phoneNumber, $email, $address);
//...
$contactData = new ContactData($phoneNumber, $email, $address);
public function setContactData(ContactData $contactData);
public function updateContactData(ContactData $contactData);
Reemplazar parámetros con métodos explícitos. Un método que requiere muchos parámetros podría estar haciendo varias cosas diferentes que se pueden separar. Si es el caso, divide el método en esas partes y haz que reciba cada una sus propios parámetros.
public function setClientData($name, $firstSurname, $secondSurname, $phoneNumber, $email, $address);
//...
public function setClientName($name, $firstSurname, $secondSurname);
public function setContactData($phoneNumber, $email, $address);
Parámetros opcionales
Los parámetros opcionales tienen el inconveniente de que complican la signatura de los métodos. En algunos casos, puede ser buena idea ofrecer métodos alternativos, que ofrezcan una signatura más sencilla de entender, ocultando el método como privado.
public function addEmail(Email $email, bool $allowMarketingNotifications = true);
// Change to private
private function addEmail(Email $email, bool $allowMarketingNotifications = true);
// Alternative explicit methods
public function addEmailAllowingMarketingNotifications(Email $email)
{
$this->addEmail($email, true);
}
public function addEmailNotAllowingMarketingNotifications(Email $email);
{
$this->addEmail($email, false);
}