[language-agnostic] 좋아하는 (영리한) 방어 프로그래밍 모범 사례 [닫기]

방어 코딩을 위해 좋아하는 (영리한) 기술 을 선택해야한다면 그 기술은 무엇입니까? 현재 사용하는 언어는 Java 및 Objective-C (C ++의 배경 지식)이지만 모든 언어로 자유롭게 대답 할 수 있습니다. 여기서 우리 중 70 % 이상이 이미 알고있는 것 이외의 영리한 방어 기술 에 중점 을 둘 것입니다. 이제 트릭을 깊이 파고들 차례입니다.

다시 말해이 흥미없는 예 이외의 다른 것을 생각해보십시오 .

  • if(5 == x) 대신 if(x == 5) : 의도하지 않은 할당을 피하기 위해

다음은 흥미로운 방어 적 프로그래밍 방법에 대한 몇 가지 예입니다 (언어 별 예는 Java로되어 있음).

-변수를 변경해야 할 때까지 변수를 잠그십시오.

즉, 변수 를 변경해야한다는 것을 알 때까지 모든 변수를 선언 할 수 있으며이 final시점에서을 제거 할 수 있습니다 final. 일반적으로 알려지지 않은 사실은 이것이 메소드 매개 변수에도 유효하다는 것입니다.

public void foo(final int arg) { /* Stuff Here */ }

-나쁜 일이 생길 때는 증거를 남기십시오

예외가있을 때 수행 할 수있는 여러 가지 작업이 있습니다. 명백하게 기록하고 정리를 수행하는 것은 몇 가지 일 것입니다. 그러나 증거의 흔적을 남길 수도 있습니다 (예 : “UNABLE TO LOAD FILE”또는 99999와 같은 센티넬 값으로 변수를 설정하면 예외 catch블록을 넘어서 버릴 경우 디버거에서 유용 할 수 있습니다 ).

-일관성에 관해서 : 악마는 세부 사항에 있습니다.

사용중인 다른 라이브러리와 일관성을 유지하십시오. 예를 들어 Java에서 값 범위를 추출하는 메소드를 작성하는 경우 하한을 포함 하고 상한을 독점으로 설정하십시오 . 이것은 String.substring(start, end)같은 방식으로 작동하는 것과 같은 방법과 일치하게합니다 . Sun JDK에서 이러한 유형의 모든 메소드는 배열이 일치하는 요소의 반복을 포함하여 다양한 작업을 수행하므로 인덱스가 0 ( 포함 )부터 배열의 길이 ( 독점 ) 까지 다양한 방식으로 작동하므로 이러한 방식으로 작동합니다 .

그렇다면 가장 좋아하는 수비 관행은 무엇입니까?

업데이트 : 아직하지 않은 경우 자유롭게 차임하십시오. 공식 답변을 선택하기 전에 더 많은 답변을 드리겠습니다.



답변

c ++에서는 펜스 포스트 오류를 ​​포착하기 위해 여분의 메모리를 제공하기 위해 새로운 재정의를 한 번 좋아했습니다.

현재 저는 테스트 주도 개발 (Test Driven Development)을 선호하는 방어 적 프로그래밍을 피하는 것을 선호합니다 . 오류를 신속하고 외부 적으로 포착하는 경우 방어적인 조작으로 코드를 어지럽 힐 필요가 없으며 코드가 건조 되어 방어해야 할 오류가 줄어 듭니다.

WikiKnowledge가 쓴대로 :

방어 프로그래밍을 피하고 대신 빨리 실패하십시오.

방어 적 프로그래밍이란 데이터의 일부 실패를 보상하는 코드 작성, 호출자가 호출자와 서브 루틴 간의 계약을 준수하지 않는 데이터를 제공 할 수 있고 서브 루틴이 어떻게 든 대처해야한다고 가정하는 코드 작성 습관을 의미합니다. 그것으로.


답변

SQL

데이터를 삭제해야 할 때

select *
--delete
From mytable
Where ...

내가 그것을 실행할 때, where 절을 잊어 버렸는지 알 수 있습니다. 안전이 있습니다. 모든 것이 괜찮다면 ‘-‘주석 토큰 다음에있는 모든 것을 강조 표시하고 실행합니다.

편집 : 많은 데이터를 삭제하는 경우 * 대신 count (*)를 사용합니다.


답변

응용 프로그램이 시작될 때 합리적인 메모리 덩어리를 할당하십시오. Steve McConnell은 이것을 Code Complete 의 메모리 낙하산 이라고 부릅니다 .

심각한 문제가 발생하여 종료해야하는 경우에 사용할 수 있습니다.

이 메모리를 미리 할당하면 여유 공간을 확보 한 후 사용 가능한 메모리를 사용하여 다음을 수행 할 수 있으므로 안전망이 제공됩니다.

  • 모든 영구 데이터 저장
  • 적절한 파일을 모두 닫습니다
  • 로그 파일에 오류 메시지 쓰기
  • 사용자에게 의미있는 오류를 제시

답변

기본 사례가없는 모든 switch 문에서 오류 메시지와 함께 프로그램을 중단하는 사례를 추가합니다.

#define INVALID_SWITCH_VALUE 0

switch (x) {
case 1:
  // ...
  break;
case 2:
  // ...
  break;
case 3:
  // ...
  break;
default:
  assert(INVALID_SWITCH_VALUE);
}


답변

열거 형 (C #)의 다양한 상태를 처리 할 때 :

enum AccountType
{
    Savings,
    Checking,
    MoneyMarket
}

그런 다음, 일상 안에서 …

switch (accountType)
{
    case AccountType.Checking:
        // do something

    case AccountType.Savings:
        // do something else

    case AccountType.MoneyMarket:
        // do some other thing

    default:
-->     Debug.Fail("Invalid account type.");
}

언젠가이 열거 형에 다른 계정 유형을 추가하겠습니다. 그리고 내가 할 때, 나는이 스위치 문장을 고치는 것을 잊을 것이다. 따라서이 Debug.Fail사실에주의를 끌기 위해 디버그 모드에서 끔찍하게 충돌이 발생합니다. 을 추가하면 case AccountType.MyNewAccountType:다른 계정 유형을 추가하고 여기에서 사례를 업데이트하는 것을 잊을 때까지 끔찍한 충돌이 중지됩니다.

(예, 다형성이 아마도 더 좋을 수도 있지만 이것은 단지 내 머리 꼭대기의 예일뿐입니다.)


답변

문자열 (특히 사용자 입력에 따라 다름)과 함께 오류 메시지를 인쇄 할 때 항상 작은 따옴표를 사용합니다 ''. 예를 들면 다음과 같습니다.

FILE *fp = fopen(filename, "r");
if(fp == NULL) {
    fprintf(stderr, "ERROR: Could not open file %s\n", filename);
    return false;
}

%s파일 이름이 빈 문자열이거나 공백 또는 무언가이기 때문에 따옴표 가 부족합니다 . 인쇄 된 메시지는 물론 다음과 같습니다.

ERROR: Could not open file

따라서 항상하는 것이 좋습니다.

fprintf(stderr, "ERROR: Could not open file '%s'\n", filename);

그런 다음 최소한 사용자에게 다음이 표시됩니다.

ERROR: Could not open file ''

최종 사용자가 제출 한 버그 보고서의 품질 측면에서 큰 차이가 있습니다. 일반적인 소리가 아닌 이와 같은 재미있는 오류 메시지가있는 경우 “내 파일을 열지 않습니다”라고 쓰지 않고 복사 / 붙여 넣기 할 가능성이 훨씬 높습니다.


답변

SQL 안전

데이터를 수정할 SQL을 작성하기 전에 롤백 트랜잭션으로 전체를 래핑합니다.

BEGIN TRANSACTION
-- LOTS OF SCARY SQL HERE LIKE
-- DELETE FROM ORDER INNER JOIN SUBSCRIBER ON ORDER.SUBSCRIBER_ID = SUBSCRIBER.ID
ROLLBACK TRANSACTION

이렇게하면 잘못된 삭제 / 업데이트를 영구적으로 실행할 수 없습니다. 또한 모든 것을 실행하고 합리적인 레코드 수를 확인하거나 SELECTSQL과 사이 에 문을 추가 하여 ROLLBACK TRANSACTION모든 것이 올바르게 표시되도록 할 수 있습니다.

완전히있을 때 확실히 당신이 기대했던의 변경 않습니다 ROLLBACKCOMMIT와 진짜 실행합니다.