Une fonction pure est celle qui:
- Donne toujours le même résultat avec les mêmes arguments
- N'a pas d'effets secondaires observables (par exemple des changements d'état)
Supposons que nous écrivons du code pour gérer la connexion utilisateur, où nous voulons vérifier que le nom d'utilisateur et le mot de passe fournis sont corrects et empêcher l'utilisateur de se connecter s'il y a trop de tentatives infructueuses. Dans un style impératif, notre code pourrait ressembler à ceci:
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;
}
C'est assez clair que ce n'est pas une fonction pure:
- Cette fonction ne donnera pas toujours le même résultat pour une donnée
username
et password
combinaison que le résultat dépend également de l'enregistrement de l' utilisateur stocké dans la base de données.
- La fonction peut changer l'état de la base de données, c'est-à-dire qu'elle a des effets secondaires.
Notez également que pour tester unitaire cette fonction, nous devons simuler deux appels de base de données, FindUser
et RecordFailedLoginAttempt
.
Si nous devions refactoriser ce code dans un style plus fonctionnel, nous pourrions nous retrouver avec quelque chose comme ceci:
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;
}
Notez que bien que la UserLogin
fonction ne soit toujours pas pure, la UserLoginPure
fonction est maintenant une fonction pure et, par conséquent, la logique d'authentification principale de l'utilisateur peut être testée unitaire sans avoir besoin de se moquer des dépendances externes. En effet, l'interaction avec la base de données est gérée plus haut dans la pile des appels.