Una función pura es aquella que:
- Será siempre el mismo resultado dado los mismos argumentos
- No tiene efectos secundarios observables (por ejemplo, cambios de estado)
Supongamos que estamos escribiendo algún código para manejar el inicio de sesión del usuario, donde queremos verificar que el nombre de usuario y la contraseña proporcionados sean correctos y evitar que el usuario inicie sesión si hay demasiados intentos fallidos. En un estilo imperativo, nuestro código podría verse así:
bool UserLogin(string username, string password)
{
var user = _database.FindUser(username);
if (user == null)
{
return false;
}
if (user.FailedAttempts > 3)
{
return false;
}
// Password hashing omitted for brevity
if (user.Password != password)
{
_database.RecordFailedLoginAttempt(username);
}
return true;
}
Está bastante claro que esta no es una función pura:
- Esta función no siempre dará el mismo resultado para un determinado
username
y password
combinación como el resultado también depende del registro de usuario almacenada en la base de datos.
- La función puede cambiar el estado de la base de datos, es decir, tiene efectos secundarios.
También tenga en cuenta que para realizar una prueba unitaria de esta función, debemos simular dos llamadas a la base de datos, FindUser
y RecordFailedLoginAttempt
.
Si tuviéramos que refactorizar este código en un estilo más funcional, podríamos terminar con algo así:
bool UserLogin(string username, string password)
{
var user = _database.FindUser(username);
var result = UserLoginPure(user, password);
if (result == Result.FailedAttempt)
{
_database.RecordFailedLoginAttempt(username);
}
return result == Result.Success;
}
Result UserLoginPure(User user, string pasword)
{
if (user == null)
{
return Result.UserNotFound;
}
if (user.FailedAttempts > 3)
{
return Result.LoginAttemptsExceeded;
}
if (user.Password != password)
{
return Result.FailedAttempt;
}
return Result.Success;
}
Tenga en cuenta que aunque la UserLogin
función aún no es pura, UserLoginPure
ahora es una función pura y, como resultado, la lógica de autenticación del usuario central puede probarse en la unidad sin necesidad de burlarse de ninguna dependencia externa. Esto se debe a que la interacción con la base de datos se maneja más arriba en la pila de llamadas.