İşlevsel stil alay bağımlılıklarına nasıl yardımcı olur?


10

Yakın zamanda bir Java Dergisi sayısında Kent Beck ile yapılan röportajdan:

Binstock: Mikro hizmetlerden bahsedelim. Bana göre, mikro hizmetlerde ilk test, bazı hizmetlerin işlev görmesi için bir dizi başka hizmetin varlığına ihtiyaç duyması açısından karmaşık hale gelecektir. Katılıyor musun?

Beck: Bir büyük sınıfa veya çok sayıda küçük sınıfa sahip olmakla aynı ticaret dizisi gibi görünüyor.

Binstock: Doğru, sanırım hariç, burada belirli bir hizmeti test edebileceğiniz bir sistem kurabilmek için çok fazla sahte kullanmanız gerekiyor.

Beck: Kabul etmiyorum. Zorunlu bir tarzda ise, çok fazla alay kullanmanız gerekir. Dış bağımlılıkların çağrı zincirinde bir araya getirildiği fonksiyonel bir tarzda, bunun gerekli olduğunu düşünmüyorum. Ünite testlerinden çok fazla kapsam alabileceğinizi düşünüyorum.

Ne demek istiyor? İşlevsel tarz sizi dış bağımlılıklarla alay etmekten nasıl kurtarabilir?



1
Özellikle Java'yı tartışıyorlarsa, bu tartışmanın çoğunun tartışmalı olduğundan şüpheleniyorum. Java, tarif edilen işlevsel programlama türüne kendini vermek için gereken desteğe sahip değildir. Elbette, simüle etmek için yardımcı program sınıflarını veya belki de Java 8 Lambdas'ı kullanabilirsiniz, ancak ... blecch.
Robert Harvey

Yanıtlar:


8

Bir saf fonksiyonu bir olmasıdır:

  1. Will hep aynı argümanlar verilen aynı sonucu verir
  2. Gözlenebilir herhangi bir yan etkisi yoktur (örn. Durum değişiklikleri)

Kullanıcı girişini işlemek için bazı kodlar yazdığımızı varsayalım, burada verilen kullanıcı adı ve parolanın doğru olup olmadığını kontrol etmek ve çok fazla başarısız deneme varsa kullanıcının oturum açmasını engellemek istiyoruz. Zorunlu bir tarzda kodumuz şöyle görünebilir:

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;
}

Bunun saf bir işlev olmadığı oldukça açıktır:

  1. Bu işlev belirli bir usernameve passwordkombinasyon için her zaman aynı sonucu vermeyecektir, çünkü sonuç aynı zamanda veritabanında saklanan kullanıcı kaydına da bağlıdır.
  2. Fonksiyon veritabanının durumunu değiştirebilir, yani yan etkileri vardır.

Ayrıca birim testi için bu fonksiyon iki veritabanı aramaları dışarı alay etmek gerek, unutmayın FindUserve RecordFailedLoginAttempt.

Bu kodu daha işlevsel bir stile dönüştürürsek, bunun gibi bir şeyle sonuçlanabiliriz:

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İşlev hala saf olmasa da, işlevin UserLoginPureartık saf bir işlev olduğunu ve bunun sonucunda çekirdek kullanıcı kimlik doğrulama mantığının harici bağımlılıklarla alay etmeden birim test edilebileceğini unutmayın. Bunun nedeni, veritabanı ile etkileşimin çağrı yığını üzerinde daha üst düzeyde ele alınmasıdır.


Yorumunuz : Emir Kipi = Durumsal Mikro Hizmetler ve İşlevsel Stil = Vatansız Mikro Hizmetler ?
k3b

@ k3b Mikro hizmetlerle ilgili bit dışında. Çok basit bir şekilde Zorunlu stil durum manipülasyonunu içerirken, fonksiyonel stil durum manipülasyonu olmadan saf fonksiyonları kullanır.
Justin

1
@ Justin: İşlevsel stilin, örnekte yaptığınız gibi, saf işlevleri yan etkilerle koddan açıkça ayırdığını söyleyebilirim. Başka bir deyişle, fonksiyonel kod hala yan etkilere sahip olabilir.
Giorgio

İşlevsel yaklaşım, sonuç ve kullanıcı içeren bir çift döndürmelidir, çünkü başarısız bir denemede, Result.FailedAttempt, bir kez daha başarısız girişimi olması ve saf bir işlev yapması dışında, orijinaliyle aynı verilere sahip yeni bir kullanıcının sonucudur. parametre olarak verilen kullanıcı üzerinde yan etkiler ortaya çıkarır.
risingDarkness

önceki yorumumun son kısmı için düzeltme: "ve saf bir işlev , parametre olarak verilen kullanıcı üzerinde yan etkiler yaratmaz ."
risingDarkness
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.