문제

저는 스토리지 시스템에 대한 인터페이스 역할을 하는 클래스 세트를 개발하는 프로젝트를 맡았습니다.요구사항은 클래스가 다음 시그니처를 사용하여 get 메소드를 지원해야 한다는 것입니다.

public CustomObject get(String key, Date ifModifiedSince)

기본적으로 이 메소드는 CustomObject 와 관련된 key 객체가 이후에 수정된 경우에만 ifModifiedSince.스토리지 시스템에 key 그러면 메서드는 null을 반환해야 합니다.

내 문제는 이것이다:

키가 존재하지만 객체가 있는 시나리오를 어떻게 처리합니까? ~ 아니다 수정됐나요?

이 클래스를 사용하는 일부 애플리케이션은 웹 서비스 및 웹 애플리케이션이기 때문에 이는 중요합니다.해당 애플리케이션은 404(찾을 수 없음), 304(수정되지 않음) 또는 200(알겠습니다. 데이터는 다음과 같습니다)을 반환할지 여부를 알아야 합니다.

제가 고려하고 있는 솔루션은 다음과 같습니다.

  1. 스토리지 시스템에key
  2. 다음과 같은 경우 사용자 정의 예외를 발생시킵니다.ifModifiedSince 실패합니다.
  3. CustomObject에 상태 속성을 추가합니다.발신자에게 속성을 확인하도록 요구합니다.

이 세 가지 옵션 중 어느 것도 만족스럽지 않습니다.나는 흐름 제어에 예외를 사용하는 것을 좋아하지 않기 때문에 옵션 1과 2를 좋아하지 않습니다.내 의도가 있었음을 나타내는 것일 때 값을 반환하는 것도 좋아하지 않습니다. 가치 없음.

그럼에도 불구하고 나는 옵션 3을 선호한다.

제가 고려하지 않은 옵션이 있나요?이 세 가지 옵션 중 하나에 대해 강한 감정을 갖고 있는 사람이 있습니까?


이 질문에 대한 답변을 다른 말로 표현하면 다음과 같습니다.

  1. 제공 contains메소드 및 발신자가 호출하기 전에 호출해야합니다 get(key, ifModifiedSince), 키가 존재하지 않으면 객체가 수정되지 않은 경우 NULL을 반환합니다.
  2. 복합 객체에 응답 및 데이터 (있는 경우)를 감싸십시오.
  3. 일부 상태를 나타내기 위해 미리 정의된 상수를 사용합니다(UNMODIFIED, KEY_DOES_NOT_EXIST).
  4. 발신자는 콜백으로 사용하도록 인터페이스를 구현합니다.
  5. 디자인이 형편없어요.

내가 답 #1을 선택할 수 없는 이유

나는 이것이 이상적인 해결책이라는 데 동의하지만 이미 (마지 못해) 무시한 해결책이었습니다.이 접근 방식의 문제점은 이러한 클래스가 사용되는 대부분의 경우 백엔드 스토리지 시스템이 Amazon S3와 같은 타사 원격 시스템이 된다는 것입니다.이는 다음을 의미합니다. contains 방법을 사용하려면 스토리지 시스템을 왕복해야 하며, 대부분의 경우 또 다른 왕복이 필요합니다.왜냐하면 이건 시간과 돈이 모두 들 것이다, 그것은 선택 사항이 아닙니다.

해당 제한이 없다면 이것이 최선의 접근 방식이 될 것입니다.

(질문에서 이 중요한 요소를 언급하지 않았다는 것을 알고 있지만 간략하게 설명하려고 노력했습니다.분명히 관련성이 있었습니다.)


결론:

모든 답변을 읽은 후 이 경우 래퍼가 가장 좋은 접근 방식이라는 결론에 도달했습니다.기본적으로 응답 코드와 콘텐츠 본문(메시지)을 포함한 메타데이터(헤더)를 사용하여 HTTP를 모방하겠습니다.

도움이 되었습니까?

해결책

실제로 응답 코드와 찾은 객체의 두 항목을 실제로 반환하려는 것 같습니다. 둘 다 고정하고 함께 반환하는 경량 래퍼를 만드는 것을 고려할 수 있습니다.

public class Pair<K,V>{
  public K first;
  public V second;
}

그런 다음 응답 코드와 데이터를 보유하는 새 쌍을 만들 수 있습니다. 제네릭 사용의 부작용으로 실제로 필요한 쌍에 대해이 래퍼를 재사용 할 수 있습니다.

또한 데이터가 만료되지 않은 경우에도 여전히 반환 할 수 있지만 303 코드를 제공하여 변경되지 않았 음을 알리십시오. 4xx 시리즈는 쌍을 이룹니다 null.

다른 팁

주어진 요구 사항을 사용하면이 작업을 수행 할 수 없습니다.

계약을 설계 한 경우, 그런 다음 조건을 추가하고 발신자가 호출하도록합니다.

exists(key): bool

서비스 구현은 다음과 같습니다.

if (exists(key)) {
    CustomObject o = get(key, ifModifiedSince);
    if (o == null) { 
      setResponseCode(302);
    } else {
      setResponseCode(200);
      push(o);
   }

} else {
      setResponseCode(400);
}

클라이언트는 변경되지 않은 상태로 유지되며 선불로 검증 된 것을 알지 못합니다.

계약을 설계하지 않은 경우 아마도 그에 대한 좋은 이유가 있거나 아마도 디자이너 (또는 건축가) 결함 일뿐입니다. 그러나 당신은 그것을 바꿀 수 없기 때문에 걱정할 필요가 없습니다.

그런 다음 사양을 준수하고 다음과 같이 진행해야합니다.

 CustomObject o = get(key, ifModifiedSince);

 if (o != null) {
     setResponseCode(200);
     push(o);
  } else {
     setResponseCode(404); // either not found or not modified.
  }

좋아,이 경우 302를 보내지는 않지만 아마도 그것이 설계된 방식 일 것입니다.

보안상의 이유로 서버는 그보다 더 많은 정보를 반환해서는 안됩니다. 프로브가 얻어집니다 (키, 날짜) 만 널 또는 객체를 반환합니다

그러니 걱정하지 마세요. 관리자와 대화 하고이 결정을 알려주십시오. 이 결정에도 코드에 댓글을 달아라. 그리고 당신이 건축가가 손에 든다면이 이상한 제한의 근거를 확인하십시오.

당신 이이 일이 오지 않았고 제안 후에 계약을 수정할 수 있습니다.

때로는 제대로 진행하고 싶을 때 우리는 잘못 진행하여 앱의 보안을 타협 할 수 있습니다.

팀과 의사 소통하십시오.

변경되지 않은 것을 나타내는 "마커"로 특수 최종 CustomObject를 만들 수 있습니다.

static public final CustomObject UNCHANGED=new CustomObject();

.quals () 대신 "=="와 일치하는 것을 테스트하십시오.

변경되지 않은 상태에서 Null을 반환하고 예외가 존재하지 않습니까? 내가 당신의 3 중 하나를 선택해야한다면, 나는 가장 예외적 인 경우 1을 선택할 것입니다.

존재하지 않는 객체를 찾는 것은 저에게 예외적 인 사례처럼 보입니다. 발신자가 객체가 존재하는지 판단 할 수있는 메소드와 함께, 그렇지 않을 때는 예외를 던지는 것이 좋을 것이라고 생각합니다.

public bool exists( String key ) { ... }

발신자는 할 수 있습니다 :

if (exists(key)) {
   CustomObject modified = get(key,DateTime.Today.AddDays(-1));
   if (modified != null) { ... }
}

or

try {
    CustomObject modified = get(key,DateTime.Today.AddDays(-1));
}
catch (NotFoundException) { ... }

예외의 문제는 "빠른 빠른"시나리오를 알리는 것입니다 (예 : 처리되지 않으면 예외는 예외입니다. 멈추다 신청서) 예외로 인해 그리고 비정상 행동.

나는 "키가 존재하지만 개체가 수정되지 않은 시나리오"는 예외적 인 시나리오라고 생각하지 않습니다.

따라서 나는 예외를 사용하지 않고 오히려 결과 (속성 또는 특수 객체)를 올바르게 해석하기 위해 발신자가해야 할 조치를 문서화 할 것입니다.

해당 방법 서명의 요구 사항은 얼마나 엄격합니까?

마치 아직 진행중인 프로젝트를 진행하는 것처럼 보입니다. 수업 소비자가 다른 개발자라면 요청한 방법 서명이 충분하지 않다고 확신 할 수 있습니까? 아마도 그들은 두 개의 고유 한 실패 모드가 있어야한다는 것을 아직 깨닫지 못했을 것입니다 (키는 존재하지 않고 객체가 수정되지 않았습니다).

옵션이라면 감독자와 논의 할 것입니다.

나는 여전히 null을 반환합니다.

속성의 의도는 지정된 날짜 이후 수정 된 개체를 반환하는 것입니다. 객체가 없을 때 Null을 반환하는 경우 괜찮은 개체에 대해 NULL을 반드시 반환하는 것도 괜찮습니다.

나는 개인적으로 수정되지 않은 개체에 대해 NULL을 반환하고 존재하지 않는 물체에 대한 예외를 던질 것입니다. 더 자연스럽게 보입니다.

흐름 제어 BTW에 예외를 사용하지 않는 것이 좋습니다. 따라서 3 가지 옵션 만 있으면 장 본능이 옳습니다.

.Net 라이브러리 패턴을 따르고 사용자 정의 개체에 공개 정적 읽기 전용 필드를 가질 수 있습니다. CustomObject.Empty 그건 유형이야 사용자 정의 개체 (예: string.Empty 및 Guid.Empty)객체가 수정되지 않은 경우 이를 반환할 수 있습니다(함수 소비자는 이를 비교해야 합니다).
편집하다: 방금 당신이 Java로 작업하고 있다는 것을 발견했지만 원칙은 여전히 ​​​​적용됩니다.

이를 통해 다음 옵션이 제공됩니다.

  • 키가 존재하지 않으면 null을 반환합니다.

  • 반품 CustomObject.Empty 키가 존재하지만 객체가 수정되지 않은 경우.

단점은 소비자가 null 반환 값과 CustomObject.Empty 반환 값 간의 차이를 알아야 한다는 것입니다.

아마도 그 부동산은 더 적절하게 불릴 것입니다. CustomObject.NotModified 빈은 실제로 null이 될 수 없는 값 유형을 위한 것입니다.또한 수정되지 않음 소비자에게 해당 분야의 의미를 보다 쉽게 ​​전달할 수 있습니다.

요구 사항에 관한 (의도 된) 인터페이스는 심각하게 깨졌습니다. 당신은 하나의 방법 내에서 관련없는 일을하려고합니다. 이것은 소프트웨어 지옥으로가는 길입니다.

콜백 클래스가 이벤트 중심이거나 세터 구동이 될 수있는 인수로서 콜백을 제공하십시오.

클래스의 인터페이스가 필요한 경우 이벤트 매개 변수로 CustomObject를 전달하는 다양한 오류를 정의해야합니다.

public interface Callback {
  public void keyDoesNotExist();
  public void notModified(CustomObject c);
  public void isNewlyModified(CustomObject c);
  .
  .
  .
}

이러한 방식으로 콜백 인터페이스의 구현자가 이벤트가 발생할 때 수행해야 할 작업을 정의 할 수 있으며, 해당 조건에 검색된 개체의 통과가 필요한지 여부에 관계없이 인터페이스를 통해 선택할 수 있습니다. 마지막으로, 반품에 대한 논리의 복잡성을 줄입니다. 당신의 방법은 한 번 그렇게합니다. API의 도구는 API를 위해 수행 할 필요가 없습니다.

허용되는 경우 객체와 수정 상태를 나타내는 값이 포함 된 증폭 된 CustomObject (래퍼)를 반환 할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top