단일 책임 원칙에 대해 걱정하지 마십시오. 특정 개념을 "책임"으로 주관적으로 선택할 수 있기 때문에 여기에서 올바른 결정을 내리는 데 도움이되지 않습니다. 클래스의 책임이 데이터베이스에 대한 데이터 지속성을 관리한다고 말하거나 사용자 작성과 관련된 모든 작업을 수행하는 책임을 말할 수 있습니다. 이들은 응용 프로그램 동작의 다른 수준 일 뿐이며 "단일 책임"이라는 유효한 개념 표현입니다. 따라서이 원칙은 문제를 해결하는 데 도움이되지 않습니다.
이 경우 가장 유용한 원칙 은 가장 놀랄만 한 원칙입니다 . 따라서 질문을 해보자 : 데이터베이스에 데이터를 유지하는 주요 역할을하는 저장소가 전자 메일을 보내는 것도 놀라운 일 입니까?
예, 정말 놀랍습니다. 이들은 완전히 별개의 두 외부 시스템이며, 이름 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 단계 커밋 전략이 필요합니다.)
결론은 실용적입니다. 실제로 코드 작성의 결과 (위험 및 이익 측면에서)를 통해 특정 방식으로 생각하십시오. "단일 책임 원칙"이 그 일을하는 데 자주 도움이되지는 않지만 "최소한 놀람의 원칙"은 종종 다른 개발자의 머리에 들어가서 어떤 일이 일어날 지 생각하는 데 도움이됩니다.