단일 책임 원칙에 대해 걱정하지 마십시오. 특정 개념을 "책임"으로 주관적으로 선택할 수 있기 때문에 여기에서 올바른 결정을 내리는 데 도움이되지 않습니다. 클래스의 책임이 데이터베이스에 대한 데이터 지속성을 관리한다고 말하거나 사용자 작성과 관련된 모든 작업을 수행하는 책임을 말할 수 있습니다. 이들은 응용 프로그램 동작의 다른 수준 일 뿐이며 "단일 책임"이라는 유효한 개념 표현입니다. 따라서이 원칙은 문제를 해결하는 데 도움이되지 않습니다.
이 경우 가장 유용한 원칙 은 가장 놀랄만 한 원칙입니다 . 따라서 질문을 해보자 : 데이터베이스에 데이터를 유지하는 주요 역할을하는 저장소가 전자 메일을 보내는 것도 놀라운 일 입니까?
예, 정말 놀랍습니다. 이들은 완전히 별개의 두 외부 시스템이며, 이름 SaveChanges이 알림을 보내는 것을 의미하지는 않습니다. 코드를 읽는 사람이 더 이상 어떤 추가 동작이 호출되는지 쉽게 알 수 없기 때문에이를 이벤트에 위임하면 동작이 더욱 놀라워집니다. 간접적 인 가독성을 손상시킵니다. 때로는 이점이 가독성 비용의 가치가 있지만 최종 사용자가 관찰 할 수있는 추가 외부 시스템을 자동으로 호출 할 때는 그렇지 않습니다. (로깅은 그 효과가 디버깅 목적으로 기본적으로 기록을 유지이기 때문에 여기에서 제외 할 수 있습니다. 사용자가 그래서 항상 로그인에 전혀 해가없는 로그를 소비하지 않습니다 종료합니다.) 더 나쁜, 이것은 유연성을 감소 타이밍 전자 메일을 보내면 저장과 알림간에 다른 작업을 인터리브 할 수 없습니다.
사용자가 성공적으로 생성 될 때 일반적으로 코드에서 알림을 보내야하는 경우 다음과 같은 방법을 만들 수 있습니다.
public void AddUserAndNotify(IUserRepository repo, IEmailNotification notifier, MyUser user)
{
repo.Add(user);
repo.SaveChanges();
notifier.SendUserCreatedNotification(user);
}
그러나 이것이 부가 가치인지 여부는 응용 프로그램의 사양에 따라 다릅니다.
실제로 SaveChanges방법 의 존재를 권장하지 않습니다 . 이 메소드는 아마도 데이터베이스 트랜잭션을 커미트하지만 다른 저장소가 동일한 트랜잭션에서 데이터베이스를 수정했을 수 있습니다 . 이 SaveChanges사용자 저장소 인스턴스에 특별히 연결되어 있기 때문에 모든 것을 커밋한다는 사실은 다시 놀랍습니다 .
데이터베이스 트랜잭션을 관리하기위한 가장 간단한 패턴은 외부 using블록입니다.
using (DataContext context = new DataContext())
{
_userRepository.Add(context, user);
context.SaveChanges();
notifier.SendUserCreatedNotification(user);
}
이를 통해 프로그래머는 모든 리포지토리에 대한 변경 사항 이 저장되는 시점을 명시 적으로 제어하고 , 커밋 전에 발생해야하는 일련의 이벤트를 코드에 명시 적으로 문서화하고, 롤백이 발생한다고 가정하고 (롤백이 발생한다고 가정 DataContext.Dispose) 숨겨진 코드를 피하도록합니다. 상태 저장 클래스 간의 연결
또한 요청시 직접 이메일을 보내지 않기를 원합니다. 대기열에 알림 의 필요성 을 기록하는 것이 더 강력합니다 . 이를 통해 더 나은 오류 처리가 가능합니다. 특히, 이메일 전송 중 오류가 발생하면 사용자 저장을 방해하지 않고 나중에 다시 시도 할 수 있으며 사용자가 작성되었지만 사이트에서 오류가 리턴되는 경우를 피할 수 있습니다.
using (DataContext context = new DataContext())
{
_userRepository.Add(context, user);
_emailNotificationQueue.AddUserCreateNotification(user);
_emailNotificationQueue.Commit();
context.SaveChanges();
}
context.SaveChanges()호출이 실패한 경우 큐 소비자는 전자 우편을 보내기 전에 사용자가 존재하는지 확인할 수 있으므로 알림 큐를 먼저 커미트하는 것이 좋습니다 . (그렇지 않으면, heisenbugs를 피하기 위해 본격적인 2 단계 커밋 전략이 필요합니다.)
결론은 실용적입니다. 실제로 코드 작성의 결과 (위험 및 이익 측면에서)를 통해 특정 방식으로 생각하십시오. "단일 책임 원칙"이 그 일을하는 데 자주 도움이되지는 않지만 "최소한 놀람의 원칙"은 종종 다른 개발자의 머리에 들어가서 어떤 일이 일어날 지 생각하는 데 도움이됩니다.