헤르메스 LIFE

에러, 버그, 예외 (Error, Bug, Exception) 본문

Core Java

에러, 버그, 예외 (Error, Bug, Exception)

헤르메스의날개 2011. 5. 3. 13:14
728x90
원문 : http://smack.kr/category/개발표준가이드라인

예러, 버그 와 예외는 프로그래머 조차도 많이 혼동하는 개념의 어휘이다.

개념이야 어떻든 프로그램이 잘 안돌아가면 그게 에러든 버그든 예외이든 구분하지 않고 그냥 에러나 버그라고 퉁쳐서 부르는 경향이 있는데, 이는 개발팀 이외의 그룹이 프로그램의 그 어떤것이 잘 안돌아가면 밑도 끝도 없이 "당신이 개발한 프로그램이 오류가 나요"라고 말하는 것과 같다.  이 말이 개발자에게 얼마나 스트래스가 된다는 것을 이해 한다면 개발자들 자체도 위의 세가지 어휘의 차이점을 구분해서 말해야 할 것이다.

아래에 책 C# and the .NET Platform , Andrew Troelsen , 장시형 역에 기술된 개념을 적는다.

버그(Bug) : 버그는 간단히 말해 프로그래머에 의한 에러이다. 예를 들어, 비관리 C++로 프로그래밍하는 경우, NULL 포인터를 호출하거나, 배열에서 오버플로우가 발생하거나, 할당된 메모리를 지우지 않은 경우(결국 메모리 누출로 이어지는)가 버그에 해당된다.

에러(error) : 에러는 버그와 달리 일반적으로 응용 프로그램의 사용자에 의해서 발생한다. 예를 들어, 사용자가 주민등록번호를 입력하는 난에 이상한 문자열을 입력하는 경우가 있을 수 있다. 프로그래머가 이러한 경우를 대비해서 적절한 예외 처리를 하지 않았다면 에러가 발생한다.

예외(exception) : 예외는 일반적으로 런타임 오류와 관련된 것으로서, 예방하기가 어렵거나 불가능한 것들이다. 더 이상 존재하지 않는 데이터베이스에 연결하려고 한다거나, 손상된 파일을 열려고 하거나, 오프라인 상태인 머신에 접속하려고 하는 경우 예외가 발생할 수 있다. 프로그래머나 사용자는 이러한 '예외적인' 경우에 대처하기가 어렵다.

p.238


무엇이 좋은 에러 처리인가?

위의 개념에 대해서 적은 것은 무엇이 좋은 예외 처리인가를 말하기 위해서이다.

예외처리(Exception) 핸들링이 존재하는 이유는 에러가 발생하긴 했지만 그 에러를 처리 방법이 없는 곳에서 에러가 발생했을때 에러 상태가 무엇인지 결정해 주기 위함이다.

우선 위의 버그(Bug)가 발생했을 때는 어떻게 처리해야 되는가, 버그의 정의를 해석해 보면 프로그램의 논리 처리 상에서 컴파일러가 감지하지 못하는 범위의 '개발 언어'자체의 구문 에러가 프로그램에 존재함을 의미하며, 이는 논리 처리 상의 정확한 구문을 사용함으로써 해결한다.

에러란 개발자가 그 처리 방법이 없는 곳에서 발생한 에러를 적절한 예외처리를 하지 않았을때 발생하는 것으로 에러는 예외를 포함하고 있다고 볼 수 있다.

그럼, 아예 프로그래머가 대처하기 어려운 것 자체가 그 정의인 ,이 예외라는 것을 어떻게 처리해야 할까?



에러처리의 방법

프로그래머가 어떠한 작업을 처리하는 함수를 만든다. 주어진 미션을 처리 하다 보니 함수가 여러기능을 담당하면서 길어진다. 프로그래머는 가독성, 유연성, 재상용성을 위해서 함수를 각각 명확한 의미를 가진 작은 단위의 기능으로 쪼갠다. 이 쪼개어진 함수들은 필요에 따라 각각 작업의 성공/실패를 보고 하도록 작성되어진다. 이는 그 함수의 숫자 만큼 if(true / false) 의 구문을 가진 복잡한 구조를 가지게 된다. 이렇게 단위 함수들이 자신의 작업 처리 성공 실패를 보고 하고 상위에서는 그 성공/실패에 따라서 적절한 처리를 하는 것이 에러 처리의 첫번째 방법이며, 상당한 역사와 지금도 성능 및 여러상황에서 상당히 유용하다.

이렇게 처리하다 보니 성공/실패는 알았지만, 단위 함수가 실패했을때 왜 실패 했는지 프로그래머들은 알고 싶어 졌다. 프로그래머들은 성공 실패 이외에도 각각의 실패 경우에 따른 실패 코드를 반환 하길 원했다. 더이상 bool이 아닌 어떠한 코드를 반환 하기로 했다. 이것도 상당히 유용했다. 하지만 에러코드의 정의가 프로그래머 마다 제각각이 되기 쉽고, 중복된 에러 코드들도 많이 발생하게 되어 COM 이후의 프로그램 언어에서는 에러코드를 반환하지 않는 것이 개발 가이드의 표준으로 받아 들여지고 있다.

에러처리의 첫번째에서 언급 되지 않은 것이 있는데 위의 구조는 호출자 함수가 피 호출자의 성공/실패에 따라서 제어 흐름을 변경하도록 되어 있다. 그런데 예외(Exception)의 상황 , 파일 열기를 실패 한다거나, 네트웍이 끊어지는 상황이 피 호출자에게 있다면 피 호출자는 성공/실패를 반환하지 못하고 흐름이 끊기는 상황이 발생하게 된다. 이 자체로서 전체 흐름이 중지되고, 사용자는 이 멈추어진 프로그램을 멍하니 기다리는 수 밖에 없다. 이런 상황에서 시스템문제라면 CLR은 SystemException을 던지게 된다. System의 어떤 이유로 문제가 발생했는지 알려 주는 매커니즘인 것이다.

자 여기에서 Exception이 등장한다.  발생한 문제의 정보를 감싸고 있는 객체가 바로 Exception 객체이다.

Exception 객체는 이 정보를 담기 위해서 여러개의 멤버를 가지고 있다.

HelpLink : 에러가 상세하게 설명되어 있는 도움말 파일의 URL을 반환한다.
InnerException : 읽기 전용 속성으로 현재 예외를 발생시킨 원인이 되는 이전 예외에 대한 정보를 얻을 때 사용된다. 이전 예외는 현재 예외의 생성자로 전달됨으로써 문서화 된다.
Message : 읽기 전용 속성으로 해당 에러에 대한 문자 형식의 설명을 반환한다. 에러 메시지 자체는 생성자 매개변수로 설정된다.
Source : 예외를 던진 어셈블리의 이름을 반환한다.
StackTrace : 읽기 전용 속성으로 예외를 유발시킨 호출들을 순서대로 나열한 문자열이 포함된다. 이 속성은 디버깅시 매우 유용하게 사용될 수 있다.
TargetSite :  읽기전용 속성으로 예외를 던진 메소드에 대해 상세하게 설명하는 MethodBase 형식을 반환한다. (ToString()은 이 메소드의 이름을 보여준다)


자. 이제 System.Exception이라는 객체까지 알았다. 이 Exception은 사용자에게 자신을 알려야 할 것이다. 어떻게 자신의 존재를 알릴까?

.NET에서 발생된 Exception은 그 Exception을 처리하는 구문까지 호출 스택을 따라서 전달 된다. 이를 Propagate라고 한다. Exception을 Catch하는 구문이 없으면 프로그램은 비 정상 종료하게 된다.

프로그래머가 프로그램을 만들었는데 이렇게 비 정상 종료하는 일이 자주 발생하면 여러 군데로 부터 불평을 듣게 될 것이다.

프로그래머는 이렇게 비 정상 종료하는 것을 막고 싶을 것이다. 이것이 바로 '예외처리' 이다.

예외 처리의 핵심은 에러가 발생하더라도 문제를 일으키거나 오작동 되지 않고 올바른 내용의 코드가 실행될 수 있다는 하는 것이다.

이때 사용되는 것이 바로 Try ~ Catch ~ Finally 블록이다.

프로그래머는 Try ~Catch ~ Finally 기술을 연마했다. 하지만 정확하게 어떤 예외가 발생할 지 모르니

try{


}catch(Exception){


}finally{
// 리소스 해제
}

구문을 예외가 발생할 수 있는 부분에 삽입하였다. 그리고, null 또는 false를 반환하게 처리 하였다.  호출자는 피호출자로 부터 성공/실패를 받았으니 제어 흐름을 바꾸어서 자신이 원하는대로 처리 할 수 있게 되었다.

자. 이제는 예외가 발생하더라도 Exception을 catch하는 구문이 있으니 Exception으로 인하여 바로 종료 되는 일은 없어졌다.  프로그래밍 바로 종료 하지 않으니 고객들의 불만이 줄었다. 에브리바디 오케이, 에브리바디 해피이다.

여기까지가 try catch 까지 사용하는 프로그래머이며, 보통 방어적인프로그램(Defensive programming)이라고 부른다.

모든 문제가 해결 되었을까.


이렇게 처리하는 방법에 대해서 STEVE MAGUIRE는 WRITING SOLID CODE에서 아래와 같이 '조용한 처치법'이라고 말하고 있다.

"
조용한 처치법

만약 당신이 핵 화학 반응기의 소프트웨어를 작성하도록 고용되었고, 심지(core)가 과열되는 경우를 처리해야 한다고 가정하자.
어떤 프로그래머들은 이런 상황을, 자동으로 심지에 물을 들어붓게 하거나, 냉각 봉(cooler rods)을 삽입하거나, 반응기를 냉각시키기 위한 할 수 있는 모든 시도를 통해서 해결하려 할 것이다.
또 다른 프로그래머들은 심지가 과열 되엇을 때, 화학 반응기 관리자에게 경고를 하는 방식을 취할 수도 있다. 컴퓨터는 여전히 자동으로 작업을 처리할 수 있고, 기사들은 사태에 대해 항상 알게 된다.

당신이라면 어떤 방식으로 코드를 구성하겠는가?
여기에 대해서 여러가지 이견이 있으리라고는 생각하지 않는다. 대개는 기사들에게 경고를 해주는 쪽을 선택할 것이다. 컴퓨터가 반응기를 정상 작동으로 회복시키는 것은 무의미하다. 심지들은 저절로 과열되지는 않는다. 이헐게 되기 위해서는 어떤 비정상적인 일이 발생해야 한다. 그리고 이렇게 될 때, 누군가는 그 비정상적인 일이 무엇인지 이해하는 것이 좋다. 그래야 같은 일이 다시 발생하지 않도록 조치할 수 있기 때문이다.

놀랍게도 , 프로그래머들은 , 특히 경험이 많은 프로그래머들은, 어떤 예기치 않은일이 발생할 때마다. 그 문제를 조용히 처리해 버리는 코드를 작성한다. 그들은 심지어 일부러 이런 상식으로 코드를 작성한다. 그리고 당신도 아마 이렇게 하고 있을지 모르겠다.

"  pp. 69.70

자! 이제 더이상 어떻게 해야 할 것인가. 기사에게 경고를 해야한다.


마이크로소프트는 예외를 어떻게 처리하고 있을까? Office 응용프로그램을 보자, 비정상 상태를 처리 할 수 없는 상황이 되면, 종료 이전의 상태를 저장하고 있다가 어플리케이션을 재시작하고 복구 함과 동시에 오류에 대해서 마이크로소프트에게 보고해주기를 요청한다.

응용프로그램 자체가 복구 할 수 없는 상태이면서 원자로를 Melting 시킬 수 있는 상황이 오는 것을 방지 하기 위해서 마이크로 소프트는 그 숭악하다고 회자되고 있는 '블루스크린'을 띄우고 windows를 재시작 시킨다.

솔직히 클라이언트에서 실행되고 있는 어플리케이션에 대해서는 개발자가 통제하기가 힘들다.
하지만, 서버 응용 프로그램 개발자라면 Exception에 의한 오작동에 대해 대응하기가 더 쉽다.
Exception을 제어할 수 없다면 발생하는 경우를 최소화 하기 위해 노력해야 할 것이다.

기사에게 경고를 하고, 냉각 봉을 삽입하는 일 이외에도 Exception를 로깅 함으로써 추적해야 한다.

try catch를 사용하는 프로그래머라면 조용한 처리를 함으로써 Exception을 감추고 예외가 없었던 것처럼 태연한척 하면 안된다.

약간의 이견이 있겠지만, catch된 exception은 로깅되어야 하고, 보고 되어야 한다.

코드 컴플리트 가이드라인
8.3 오류 처리 기법
중립적인 값을 리턴하라
다음에 오는 타당한 값을 리턴하라
이전과 동일한 값을 리턴하라
가까운 타당한 값으로 대체하라
경고 메시지를 파일에 기록하라
오류 코드를 리턴하라
오류 처리 루틴이나 객체를 호출하라
오류가 발생한 곳에서 오류 메시지를 출력하라
지역적으로 가장 잘 작동하는 방법으로 오류를 처리하라
종료하라



참조서적 :
1. Inside C#  , Tom Archer , 김태현, 하정희 편역, 정보문화사 , [Chapter 12, 예외(Exception)를 이용한 에러 핸들링]
2. C#과 닷넷 플랫폼, Andrew Troelsen, 장시형 역, 사이텍미디어 , [5장, 예외와 객체수명]
3. WRITING SOLID CODE, Steve Maguire, 나윤석.이을재 공역, 높이깊이, p.69.70
4. Code Complete 2nd Edition, 스티브 맥코넬, 서우석 역, 정보문화사, 8장 방어적인 프로그래밍 pp289~ 312
5. The Practice of Programming , 브라이언.w.커니핸, 롭파이크, 김정민.장혜식,신성국 역, 인사이트, pp 153~157
6. 켄트 벡의 구현패턴 , 켄트백, 전동환 역, 에이콘 출판사, pp. 116 ~ 121


Exception 포스트
http://www.onjava.com/pub/a/onjava/2003/11/19/exceptions.html
http://today.java.net/pub/a/today/2003/12/04/exceptions.html
http://today.java.net/pub/a/today/2006/04/06/exception-handling-antipatterns.html



[객체지향 적으로 생각하라. The Object-Oriented Thought Proecess], 맷 와이스펠트 , p.91~95
Tyma, Torok, Downing [Java Primer Plus] p.223
Gilbert, McCarty [Object-Oriented Design in Java] p.139
1. 문제를 무시한다.
2. 잠재적인 문제가 있는지 점검하고 문제를 발견하면 프로그램을 취소한다.
3. 잠재적인 문제가 있는지 점검하고 실수한 것을 찾아내어 문제 해결을 시도한다.
4. 예외를 던진다. (상황을 처리할 때 선호하는 방법일 경우가 많다.)

728x90