Чистая функция является тот , который:
- Буду всегда дают тот же результат , учитывая те же аргументы
- Не имеет видимых побочных эффектов (например, изменения состояния)
Предположим, мы пишем некоторый код для обработки входа пользователя, где мы хотим проверить правильность введенных имени пользователя и пароля и предотвратить вход пользователя в систему, если слишком много неудачных попыток. В императивном стиле наш код может выглядеть так:
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;
}
Довольно ясно, что это не чистая функция:
- Эта функция не всегда дает тот же результат для заданного
username
и password
комбинации , как результат также зависит от записи пользователя , хранящейся в базе данных.
- Функция может изменять состояние базы данных, то есть имеет побочные эффекты.
Также обратите внимание, что для модульного тестирования этой функции нам нужно смоделировать два вызова базы данных, FindUser
и RecordFailedLoginAttempt
.
Если бы мы реорганизовали этот код в более функциональный стиль, мы могли бы получить что-то вроде этого:
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;
}
Обратите внимание, что хотя UserLogin
функция все еще не является чистой, UserLoginPure
функция теперь является чистой функцией, и в результате логика аутентификации пользователя может быть проверена модульно, без необходимости имитировать какие-либо внешние зависимости. Это связано с тем, что взаимодействие с базой данных обрабатывается выше стека вызовов.