Tek sorumluluk ilkesi hakkında endişelenme. Burada iyi bir karar vermenize yardımcı olmayacaktır, çünkü sübjektif bir kavramı “sorumluluk” olarak seçebilirsiniz. Sınıfın sorumluluğunun veritabanında veri kalıcılığını yönetmek olduğunu söyleyebilir ya da sorumluluğunun bir kullanıcı oluşturmakla ilgili tüm işleri yapmak olduğunu söyleyebilirsin. Bunlar, uygulamanın davranışının sadece farklı seviyeleridir ve her ikisi de "tek bir sorumluluğun" geçerli kavramsal ifadeleridir. Yani bu ilke, probleminizi çözmede yararsızdır.
Bu durumda uygulanacak en faydalı ilke, en az sürpriz ilkesidir . Öyleyse soruyu soralım: Sürdürülen verinin birincil rolü olan bir veri tabanına sahip bir havuzun da e-posta göndermesi şaşırtıcı mıdır?
Evet, çok şaşırtıcı. Bunlar birbirinden tamamen ayrı iki harici sistemdir ve ad SaveChanges
aynı zamanda bildirim gönderme anlamına da gelmez. Bunu bir olaya devretme gerçeği, davranışı daha da şaşırtıcı kılar, çünkü kodu okuyan bir kişi artık hangi ek davranışların çağrıldığını kolayca göremez. Dolaylı okunabilirliğe zarar verir. Bazen, faydalar okunabilirlik maliyetlerine değer olabilir, ancak otomatik olarak son kullanıcılar için gözlemlenebilir etkileri olan ek bir harici sistemi çalıştırdığınızda. (Etki, hata ayıklama amacıyla temelde kayıt tutma olduğundan, kayıt işlemi burada hariç tutulabilir. Son kullanıcılar günlüğü kullanmaz, bu nedenle her zaman günlüğe kaydetmenin zararı olmaz.) Daha da kötüsü, zamanlamadaki esnekliği azaltır e-postanın gönderilmesi, kaydetme ve bildirim arasındaki diğer işlemlerin birleştirilmesini olanaksız kılar.
Kodunuzun tipik olarak bir kullanıcı başarıyla oluşturulduğunda bir bildirim göndermesi gerekiyorsa, aşağıdakileri yapan bir yöntem oluşturabilirsiniz:
public void AddUserAndNotify(IUserRepository repo, IEmailNotification notifier, MyUser user)
{
repo.Add(user);
repo.SaveChanges();
notifier.SendUserCreatedNotification(user);
}
Ancak bunun değer katıp katmadığı, uygulamanızın özelliklerine bağlıdır.
Aslında SaveChanges
yöntemin varlığından vazgeçirirdim . Bu yöntem muhtemelen bir veritabanı işlemi gerçekleştirecektir, ancak diğer havuzlar veritabanını aynı işlemde değiştirmiş olabilir . Hepsini işlediği gerçeği yine şaşırtıcıdır, çünkü SaveChanges
kullanıcı havuzunun bu örneğine özel olarak bağlıdır.
Bir veritabanı işlemini yönetmek için en basit desen bir dış using
bloktur:
using (DataContext context = new DataContext())
{
_userRepository.Add(context, user);
context.SaveChanges();
notifier.SendUserCreatedNotification(user);
}
Bu, programcıya, tüm depolar için yapılan değişiklikler kaydedildiğinde açık bir kontrol sağlar , kodu bir taahhütten önce yapılması gereken olayların sırasını açıkça belgelendirmeye zorlar, bir geri dönüşün hatayla yapılmasını sağlar (bir geri dönüş yayınladığını varsayar DataContext.Dispose
) ve gizlenmeyi önler durum bilgisi olan sınıflar arasındaki bağlantılar.
Ayrıca isteği doğrudan e-postayla göndermemeyi tercih ederim. Kuyruktaki bir bildirime duyulan ihtiyacı kaydetmek daha sağlam olurdu . Bu, daha iyi arıza yönetimi için izin verir. Özellikle, e-posta gönderilirken bir hata oluşursa, daha sonra kullanıcıyı kaydetmeyi kesmeden tekrar denenebilir ve kullanıcının yaratıldığı durumdan kaçınır ancak bir hata site tarafından döndürülür.
using (DataContext context = new DataContext())
{
_userRepository.Add(context, user);
_emailNotificationQueue.AddUserCreateNotification(user);
_emailNotificationQueue.Commit();
context.SaveChanges();
}
Önce bildirim kuyruğunu işlemek daha iyidir, çünkü kuyruğun tüketicisi, context.SaveChanges()
çağrı başarısız olursa , kullanıcının e-postayı göndermeden önce var olduğunu doğrulayabilir . (Aksi takdirde, heisenbug'ları önlemek için tamamen gelişmiş iki aşamalı bir taahhüt stratejisine ihtiyacınız olacak.)
Alt satırda pratik olmaktır. Aslında kod yazmanın sonuçları (hem risk hem de fayda açısından) belirli bir şekilde düşünün. "Tek sorumluluk ilkesi" nin bunu yapmamda pek yardımcı olmadığını, "en az sürpriz ilkesi" de sık sık başka bir geliştiricinin kafasına girmeme (konuşmak için) ve ne olabileceğini düşünmeme yardımcı olduğunu biliyorum.