Llamaría a la práctica "explícita de lo contrario" a la que se refiere como un antipatrón, ya que oscurece el hecho de que no hay un código de caso especial como otra cosa para su if.
La legibilidad / mantenibilidad generalmente mejora cuando en su mayoría no tiene más que construcciones de flujo de código necesarias, y las minimiza. Esto significa elses redundantes y los if que agregarán un alcance a una función completa hacen que seguirlo y mantenerlo sea más difícil.
Digamos, por ejemplo, que tiene esta función:
public void ConfigureOblogon(Oblogon oblogonToConfigure)
{
if (_validColors.Contains(oblogonToConfigure.Color))
{
oblogonToConfigure.ColorIndex = _validColors.IndexOf(oblogonToConfigure.Color);
}
else
{
oblogonToConfigure.Color = _validColors[0];
oblogonToConfigure.ColorIndex = 0;
}
}
Ahora, el requisito es que durante la configuración también debe especificar el tipo / índice de tipo del oblogon, hay varios ámbitos en los que alguien podría colocar ese código y terminar con un código no válido, es decir
public void ConfigureOblogon(Oblogon oblogonToConfigure)
{
if (!_validOblogons.Contains(oblogonToConfigure.Type))
{
oblogonToConfigure.Type = _validOblogons[0];
oblogonToConfigure.TypeIndex = 0;
if (_validColors.Contains(oblogonToConfigure.Color))
{
oblogonToConfigure.ColorIndex = _validColors.IndexOf(oblogonToConfigure.Color);
}
else
{
oblogonToConfigure.Color = _validColors[0];
oblogonToConfigure.ColorIndex = 0;
}
}
else
{
oblogonToConfigure.TypeIndex = _validOblogons.IndexOf(oblogonToConfigure.Type);
}
}
Compare esto con si el código original se escribió con construcciones de flujo de control mínimas necesarias y minimizadas.
public void ConfigureOblogon(Oblogon oblogonToConfigure)
{
if (!_validColors.Contains(oblogonToConfigure.Color))
{
oblogonToConfigure.Color = _validColors[0];
}
oblogonToConfigure.ColorIndex = _validColors.IndexOf(oblogonToConfigure.Color);
}
Ahora sería mucho más difícil poner accidentalmente algo en el alcance incorrecto o terminar con los ámbitos de hinchazón que causan duplicación en el crecimiento y el mantenimiento a largo plazo de esta función. Además, es obvio cuáles son los posibles flujos a través de esta función, por lo que se mejora la legibilidad.
Lo sé, el ejemplo es un poco artificial, pero he visto muchas veces
SomeFunction()
{
if (isvalid)
{
/* ENTIRE FUNCTION */
}
/* Nothing should go here but something does on accident, and an invalid scenario is created. */
}
Entonces, formalizar esas reglas sobre construcciones de flujo de control creo que puede ayudar a la gente a desarrollar la intuición necesaria para oler algo cuando comienzan a escribir código como ese. Entonces comenzarán a escribir ...
SomeFunction()
{
if (!isvalid)
{
/* Nothing should go here, and it's so small no one will likely accidentally put something here */
return;
}
/* ENTIRE FUNCTION */
}
elseparece falsa. Muy a menudo, simplemente no hay nada que poner en elelsebloque a menos que se doble hacia atrás.