Một hàm thuần túy là một hàm :
- Sẽ luôn đưa ra cùng một kết quả với cùng một lý lẽ
- Không có bất kỳ tác dụng phụ nào có thể quan sát được (ví dụ: thay đổi trạng thái)
Giả sử chúng tôi đang viết một số mã để xử lý đăng nhập của người dùng, nơi chúng tôi muốn kiểm tra xem tên người dùng và mật khẩu được cung cấp có đúng không và ngăn người dùng đăng nhập nếu có quá nhiều lần thử thất bại. Trong một phong cách bắt buộc, mã của chúng tôi có thể trông như thế này:
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;
}
Rõ ràng rằng đây không phải là một chức năng thuần túy:
- Hàm này sẽ không luôn đưa ra cùng một kết quả cho một kết hợp
username
và cho trước password
vì kết quả cũng phụ thuộc vào hồ sơ người dùng được lưu trữ trong cơ sở dữ liệu.
- Hàm có thể thay đổi trạng thái của cơ sở dữ liệu, tức là nó có tác dụng phụ.
Cũng lưu ý rằng để kiểm tra đơn vị chức năng này, chúng ta cần mô phỏng hai cuộc gọi cơ sở dữ liệu FindUser
và RecordFailedLoginAttempt
.
Nếu chúng ta tái cấu trúc mã này thành một kiểu chức năng hơn, chúng ta có thể sẽ có một cái gì đó giống như thế này:
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;
}
Lưu ý rằng mặc dù UserLogin
chức năng vẫn không thuần túy, UserLoginPure
chức năng hiện là chức năng thuần túy và kết quả là logic xác thực người dùng cốt lõi có thể được kiểm tra đơn vị mà không cần phải giả định bất kỳ phụ thuộc bên ngoài nào. Điều này là do sự tương tác với cơ sở dữ liệu được xử lý cao hơn trong ngăn xếp cuộc gọi.