반환하는 것이 더 좋은 데이터베이스 관련 방법 설계 : true / false 또는 row 영향?


10

데이터베이스에서 일부 데이터 변경 (삽입, 업데이트 및 삭제)을 수행하는 몇 가지 방법이 있습니다. ORM은 내가 방법을 그 유형에 대한 반환 행에 영향을 INT 값을 사용하고 있습니다. 작업의 성공 / 실패 상태를 나타 내기 위해 "내 방법"으로 무엇을 반환해야합니까?

다음을 리턴하는 코드를 고려하십시오 int.

A.1

public int myLowerLevelMethod(int id) {
    ...
    int affectedRows = myOrm.deleteById(id)
    ...

    return affectedRows;
}

그런 다음 사용법 :

A.2

public void myOtherMethod() {
    ...
    int affectedRows = myLowerLevelMethod(id)

    if(affectedRows > 0) {
        // Success
    } else {
        // Fail
    }
}

부울 사용과 비교 :

B.1

public boolean myLowerLevelMethod(int id) {
    ...
    int affectedRows = myOrm.deleteById(id)
    ...

    return affectedRows > 0;
}

그런 다음 사용법 :

B.2

public void myOtherMethod() {
    ...
    boolean isSuccess = myLowerLevelMethod(id)

    if(isSuccess) {
        // Success
    } else {
        // Fail
    }
}

어느 것이 더 좋습니까 (A 또는 B)? 아니면 각각의 장단점?


"A.2"에서 제로 행이 영향을받는 경우 제로 행이 영향을 받아야하는 이유는 무엇입니까? 즉, 데이터베이스 오류가없는 경우 왜 실패입니까?
Jaydee

5
"성공하지 못함"과 "제로 행 영향을 받음"사이에는 의미 상 차이가 있습니까? 예를 들어, 고객의 모든 주문을 삭제할 때 "고객이 존재하지 않음"과 "고객이 주문이 없음"간에 차이가 있습니다.
Cephalopod

행이 0 인 예상치 않은 삭제를 고려하십니까? 이 경우 던져.
usr

@ 아리안 나는 그것이 진짜 질문이라고 생각합니다. A를, 내 코드는 지금 어떤 장소에서 0과 검사 -1 다른 사람이 포함되어 있기 때문에 내가 B를 선택했다 거라고 생각
호앙 트란

답변:


18

또 다른 옵션은 기본 유형 대신 결과 객체를 반환하는 것입니다. 예를 들면 다음과 같습니다.

OperationResult deleteResult = myOrm.deleteById(id);

if (deleteResult.isSuccess()) {
    // ....
}

이를 통해 어떤 이유로 영향을받는 행 수를 리턴해야하는 경우 OperationResult에 메소드를 추가 할 수 있습니다.

if (deleteResult.isSuccess()) {
    System.out.println("rows deleted: " + deleteResult.rowsAffected() );
}

이 디자인을 통해 시스템은 기존 코드를 수정하지 않고도 새로운 기능 (영향을받는 행에 대한 정보)을 확장하고 포함 할 수 있습니다.


2
+1 "이 디자인은 기존 코드를 수정하지 않고도 시스템이 확장되고 새로운 기능 (영향을받는 행에 대해 알고 있음)을 포함 할 수있게합니다."이 범주의 질문에 대한 올바른 생각입니다.
정보 : A

나는 오래된 프로젝트에서 비슷한 일을했습니다. 래퍼 요청 및 결과 개체가 있습니다. 둘 다 컴포지션을 사용하여 자세한 내용을 포함합니다. 둘 다 기본 데이터를 가지고 있습니다. 이 경우 결과 개체에는 상태 코드와 msg 필드가 있습니다.
정보 : A

특히 ORM을 사용하는 시스템의 경우이 모범 사례를 호출합니다. 해당 ORM에는 이미 이러한 결과 개체 유형이 포함되어있을 수 있습니다!
Brian S

OPs 예제를 살펴보면 deleteById가 어느 시점에서 2를 반환한다는 것입니다 :) 확실히 사용자 정의 유형입니다.
deadsven

나는이 접근법을 좋아한다. 나는 그것이 비 차단 적이라고 생각하고, 나의 접근 방식과 수정 가능 / 확장 가능 (나중에 필요할 경우)을 모두 커버한다. 내가 생각할 수있는 유일한 단점은 코드가 조금 더 많다는 것입니다. 특히 프로젝트 중간에 올 때 특히 그렇습니다. 이것을 답변으로 표시하겠습니다. 감사합니다.
Hoang Tran

12

영향을받는 행 수를 반환하면 작업 진행 방법에 대한 추가 정보가 제공되므로 더 좋습니다.

작업 중에 변경 사항이 있는지 확인하기 위해 이것을 작성해야하기 때문에 프로그래머가 당신을 비난하지 않습니다.

if(affectedRows > 0) {
    // success
} else {
    // fail
}

그러나 그들은 영향을받는 행의 수를 알아야 할 때 당신을 비난 할 것이며 그 수를 얻는 방법이 없다는 것을 깨닫습니다.

BTW : "실패"라는 의미에서 구문 쿼리 오류 (이 경우 영향을받는 행 수가 분명히 0 임)를 의미하는 경우 예외를 던지는 것이 더 적합합니다.


4
당신이 준 이유 때문에 -1. 추가 정보를 제공하는 것이 항상 좋은 생각은 아닙니다. 종종 더 나은 디자인으로 인해 필요한 것만으로도 발신자와 통신 할 수있었습니다.
Arseni Mourzenko

1
@MainMa는 오버로드 된 메소드를 생성하는 데 아무런 의미가 없습니다. 또한 모국어 (예 : C 계열)에서는 행 수를 논리에 직접 사용할 수 있습니다 (0은 거짓, 다른 것은 참).
PTwr

@PTwr : 메소드가 너무 많은 정보를 반환한다는 사실에 대처하기 위해 과부하를 생성하는 것이 좋습니다. 이것은 옳지 않은 것 같습니다. "제로가 거짓, 제로가 아닌 것이 사실"에 관해서는, 이것은 내 의견의 요점이 아니며 일부 언어에서는 나쁜 습관입니다.
Arseni Mourzenko

1
아마도 나는 트릭 을 사용하는 것이 좋은 습관으로 간주 될 수 있다고 생각하지 않기 때문에 버릇없는 프로그래머 중 하나입니다 . 사실, 다른 사람의 코드를 다루어야 할 때마다 나는 그것을 작성한 사람에게 감사 하고 어떤 트릭도 사용 하지 않았습니다 .
proskor

4
여기에 영향을받는 행 수를 항상 반환해야합니다! 행 수 = 0이 실패인지 아니면 행 수 = 3이 성공인지 알 수 없기 때문에? 누군가 3 행을 삽입하고 2 행만 삽입하려는 경우 true를 반환하지만 올바르지 않습니다! 그리고 누군가가 update t set category = 'default' where category IS NULL영향을받는 행을 0으로 만들고 싶다면 행이 영향을받지 않아도 범주가없는 항목이 없기 때문에 성공합니다!
팔코

10

나는 그들 중 어느 것도 추천하지 않을 것입니다. 대신, 성공하면 아무것도 반환하지 않고 (void) 실패하면 예외를 발생시킵니다.

이것은 내가 개인 클래스의 특정 멤버를 선언하기로 선택한 것과 정확히 같은 이유로입니다. 또한 기능을보다 쉽게 ​​사용할 수 있습니다. 더 많은 운영 컨텍스트가 항상 더 나은 것은 아니지만 더 복잡한 것을 의미합니다. 약속이 적을수록 추상화가 많을수록 고객이 이해하기 쉬우 며 구현 방법을 선택할 때 더 많은 자유를 누릴 수 있습니다.

문제는 성공 / 오류를 나타내는 방법입니다. 이 경우 예외를 던져서 실패를 알리고 성공하면 아무것도 반환하지 않아도됩니다. 사용자에게 필요한 것보다 더 많은 것을 제공해야하는 이유는 무엇입니까?

실패 / 예외 상황이 발생할 수 있으며이를 처리해야합니다. try / catch를 사용하여 리턴 코드를 검사하는지 여부는 스타일 / 개인 환경 설정의 문제입니다. try / catch의 기본 개념은 정상 흐름과 예외적 인 흐름을 분리하고 예외를 가장 적절하게 처리 할 수있는 계층으로 버블 링시킵니다. 따라서 많은 사람들이 이미 지적했듯이 실패가 실제로 예외적인지 여부에 달려 있습니다.


4
-1 왜 부가적인 운영 컨텍스트를 제공하는 부정적인 부작용없이 무언가를 반환 할 수있는 곳에 아무것도 반환하지 않겠습니까?
FreeAsInBeer

7
정확히 같은 이유로 나는 개인 클래스의 특정 멤버를 선언하기로 결정했습니다. 또한 기능을보다 쉽게 ​​사용할 수 있습니다. 더 많은 운영 컨텍스트가 항상 더 나은 것은 아니지만 더 복잡한 것을 의미합니다. 약속이 적을수록 추상화가 많을수록 고객이 이해하기 쉬우 며 구현 방법을 선택할 때 더 많은 자유를 누릴 수 있습니다.
proskor

1
사용자가 실제로 어떤 데이터를 가져와야합니까? 문제는 성공 / 오류를 나타내는 방법입니다. 이 경우 예외를 던져서 실패를 알리고 성공하면 아무것도 반환하지 않아도됩니다. 사용자에게 필요한 것보다 더 많은 것을 제공해야하는 이유는 무엇입니까?
proskor

4
@proskor : 예외적 인 경우는 예외입니다. 이 시나리오의 "실패"는 예상되는 결과 일 수 있습니다. 반드시 이것을 잠재적 인 대안으로 제시하십시오. 그러나 권장 할만한 정보가 충분하지 않습니다.
Nick Barnes

1
-1 예외는 정상적인 프로그램 흐름의 일부가되어서는 안됩니다. 오류 상황에서 "실패"가 무엇을 의미하는지는 확실하지 않지만 데이터베이스 호출 상황에서 예외는 데이터베이스에서 발생하는 예외 때문입니다. 제로 행에 영향을 미치는 것은 예외 가 아니 어야합니다 . 구문 분석 할 수없고 존재하지 않는 테이블을 참조하는 맹 글링 된 쿼리는 데이터베이스 엔진이 질식하여 던지기 때문에 예외가됩니다.

2

"이것보다 나은가요?" 두 대안이 똑같은 일을하지 않을 때 유용한 질문이 아닙니다.

영향을받는 행 수를 알아야하는 경우 버전 A 를 사용해야합니다 . 필요하지 않은 경우 버전 B를 사용할 수 있지만 코드 작성 노력이 줄어든 이점은 이미 사라졌습니다. 두 버전을 온라인 포럼에 게시하는 데 어려움을 겪었습니다!

내 요점은 어떤 솔루션이 더 낫다는 것이 전적으로이 응용 프로그램에 대한 요구 사항이 무엇인지에 달려 있으며, 이러한 상황을 우리보다 훨씬 잘 알고 있다는 것입니다. 산업 전반에 걸쳐 사용하기에 안전하고 모범 사례가 없으며 일반적으로 더 나은 선택은 없습니다 . 스스로 생각해야합니다 이 결정만큼 쉽게 결정을 내릴 때 생각하는 데 많은 시간을 소비 할 필요는 없습니다.


나는 이것이 앱 요구 사항에 많이 의존한다는 것에 동의합니다. 그러나 이런 종류의 상황은 매우 독창적이지 않은데, 나는 은색 총알을 찾고 있지 않지만 같은 / 비슷한 것을 다루는 다른 사람의 경험 (질문이 약간 오도 될 수도 있지만 A 이외의 제안을 좋아합니다) / B)
Hoang Tran

1

유지 관리 가능한 소프트웨어 설계에서 가장 중요한 두 가지 원칙은 KISSYAGNI 입니다.

  • 키스 : 간단하게 유지, 바보
  • YAGNI : 당신은 그것을 필요로하지 않습니다

지금 당장 필요하지 않은 논리를 사용하는 것은 좋은 생각이 아닙니다 . 다른 많은 사람들 중에서도, StackExchange의 공동 설립자 인 Jeff Atwood 는 이것대해 썼으며 , 내 경험상이 개념의 다른 지지자들은 완전히 옳습니다.

프로그램에 추가하는 모든 복잡성은 오랜 시간에 걸쳐 비용이 발생합니다. 프로그램은 읽기 어려워지고, 변경하기가 더 복잡해지고, 버그가 발생하기 쉬워집니다. "만약"상황을 추가하는 함정에 빠지지 마십시오. 잘못된 보안 감각입니다.

처음에는 코드를 거의 얻지 못할 것입니다. 변화는 불가피하다. 미래에 알려지지 않은 비상 사태를 방어 적으로 준비하기 위해 추론 적 논리를 추가하는 것은 미래가 예상과 다른 것으로 판명 될 때 코드를 리팩토링 하지 않아도 실제로 보호하지 않습니다 . 불필요하거나 우발적 인 로직을 유지하는 것은 나중에 누락 된 기능을 추가하기 위해 리팩토링하는 것보다 유지 보수성 문제입니다.

따라서 현재 프로그램에 필요한 모든 것은 작업의 성공 또는 실패 여부를 아는 것이므로 제안 된 솔루션 B (단일 부울 리턴)가 올바른 접근 방법입니다. 요구 사항이 변경되면 언제든지 나중에 리팩터링 할 수 있습니다. 이 솔루션은 가장 단순하고 복잡성이 가장 낮으며 (KISS) 필요한 것만 더 이상 수행하지 않습니다 (YAGNI).


-1

전체 행 또는 오류 상태

적어도 런타임 옵션으로 전체 행을 반환하는 것을 고려하십시오. DB 삽입에서는 삽입 된 데이터를 검사해야 할 수 있습니다. 종종 DB에 전송 한 것과 달라지기 때문입니다. 일반적인 예로는 자동 생성 된 행 ID (앱이 즉시 필요할 것임), DB에서 결정한 기본값 및 사용하는 경우 트리거 결과가 있습니다.

반면에 반환 된 데이터가 필요하지 않은 경우 영향을받는 행 수도 필요하지 않습니다. 0의 결과에는 도움이되지 않기 때문입니다. 실수가있는 경우 어떤 종류 의 데이터를 반환해야합니까 ? 프로젝트 오류 처리 원칙 (예외, 숫자 오류 코드 등)과 일치하는 방식으로 실수가 발생했습니다. 그러나 0 개의 행에 올바르게 영향을 미치는 유효한 쿼리가 있습니다 (예 : "만료 된 모든 주문 삭제").

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.