Sebuah fungsi murni adalah salah satu yang:
- Akan selalu memberikan hasil yang sama dengan argumen yang sama
- Tidak memiliki efek samping yang dapat diamati (misalnya perubahan status)
Misalkan kita sedang menulis beberapa kode untuk menangani login pengguna, di mana kita ingin memeriksa apakah nama pengguna dan kata sandi yang diberikan benar dan mencegah pengguna masuk jika ada terlalu banyak upaya gagal. Dalam gaya imperatif, kode kita mungkin terlihat seperti ini:
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;
}
Cukup jelas bahwa ini bukan fungsi murni:
- Fungsi ini tidak akan selalu memberikan hasil yang sama untuk yang diberikan
username
dan password
kombinasi karena hasilnya juga tergantung pada catatan pengguna yang disimpan dalam database.
- Fungsi ini dapat mengubah keadaan database, yaitu memiliki efek samping.
Juga perhatikan bahwa untuk menguji unit fungsi ini kita perlu mengejek dua panggilan basis data, FindUser
dan RecordFailedLoginAttempt
.
Jika kita memperbaiki kode ini menjadi gaya yang lebih fungsional kita mungkin berakhir dengan sesuatu yang sedikit seperti ini:
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;
}
Perhatikan bahwa meskipun UserLogin
fungsinya masih tidak murni, UserLoginPure
fungsi tersebut sekarang merupakan fungsi murni dan sebagai hasilnya logika otentikasi pengguna inti dapat diuji unit tanpa perlu mengejek setiap dependensi eksternal. Ini karena interaksi dengan basis data ditangani lebih tinggi dari tumpukan panggilan.