이 장에서 다룰 내용
•
예외 처리 모범 사례
•
버그와의 동거
•
의도적 예외 처리
•
디버깅 방지
•
고무 오리 디버깅
•
소프트웨어 개발은 프로그램의 본질적인 예측 불가능성 때문에 굉장히 복잡하다.
•
이것이 튜링 기계의 본질이며 따라서 튜링 기계의 특성상 버그를 피할 수 없다.
•
따라서 버그가 없는 프로그램을 만들기란 불가능하며 소프트웨어 개발에 착수하기 전에 먼저 이 사실을 받아들이는 것이 여러분의 일을 더 쉽게 만들 것이다.
1. 버그를 수정하지 마라
•
어느정도 규모가 있는 개발팀이라면 어떤 버그를 수정할 것인지 결정하기 위한 트리아지 프로세스를 가지고 있어야 한다.
◦
트리아지라는 용어는 1차대전 당시 의료진이 아직 생존 가능성이 높은 사람에게 제한된 자원을 할당했던 결정에서 유래되었다.
•
버그의 우선순위와 심각성을 판단하여 무엇부터 수정해야할 지 결정하라.
◦
이 둘의 적절한 임계값을 설정하여 그 밑의 버그는 후순위로 미뤄두어야 한다.
우선순위 | 심각성 | 실제 의미 |
높음 | 높음 | 즉시 고쳐라 |
높음 | 낮음 | 사장이 수정을 원한다. |
낮음 | 높음 | 인턴에게 수정하라고 지시하라. |
낮음 | 낮음 | 고치지 않는다. 사무실에 다른 할 일이 없지 않는 이상 절대 고치지 마라. 할 일이 없더라도 인턴이 고치도록 둬라. |
2. 오류에 대한 두려움
•
개발자는 본능적으로 모든 오류를 버그로 간주하고 지속적이고 끈질기게 제거하려 노력한다.
•
이런 식의 추론은 보통 알 수 없는 오류 상황으로 이어진다. 이는 무언가가 잘못되었을 때 개발자가 그것이 정말로 오류인지 아닌지 이해하는 것에 신경쓰지 않기 때문이다.
•
모든 오류를 동일한 방식으로 처리하려 하는 것을 해결하는 방법은 오류를 상태 중 하나로 생각하는 것이다.
1. 예외에 대한 진실
•
특정한 상태 중 하나이나 예상치 못했던 것이 뭘까? 바로 예외다.
•
예외는 정의되지 않는 상태 문제를 해결하는 방법 중 하나로 일반적인 흐름에서 제어되지 않는다.
•
예외가 발생하더라도 앱을 손상된 상태로 놔두어서는 안 된다.
2. 예외를 잡아내지 마라
•
예외를 무시하는 코드를 작성하는 경우가 많다.
•
예외를 두려워하지 마라. 예외가 있다는 것만으로 어딘가 충돌이 발생했음을 알 수 있다. 비어있는 catch 블록이 불러울 문제를 두려워하라.
•
예외 처리의 첫 번째 규칙은 예외를 처리하지 않는 것이다. 두 번째 규칙은 IndexOutOfRangeException이다.
◦
이 예외가 잘못된 동작때문에 발생하는 것이라면 수정하라.
◦
이미 알고 있는 이유 때문이라면 그것을 예외 처리 문에 작성하라.
•
코드의 어느 지점에서 예외가 발생할 가능성이 있을 때마다 스스로에게 이 예외를 위해 계획된 특정 수단이 있는가? 아니면 충돌을 피하기만 해도 될까?라고 질문하라.
◦
후자의 경우라면 예외를 처리할 필요가 없을 수 있고 되려 독이 될 수 있다.
•
모든 예외를 잡아내기 위한 catch 블록은 로깅과 같은 일반적인 목적으로 세상에 존재하는 모든 예외를 정말로 잡아내야할 때 사용해야 한다.
3. 예외 복원성
•
코드에 충돌이 발생할 경우에도 예외 처리 없이 올바르게 동작해야 한다.
◦
예외가 계속 발생하더라도 잘 작동하는 흐름을 설계해야 하며, 오염된 상태가 전이되지 않도록 만들어야 한다.
◦
그 이유는 예외가 불가피하기 때문이다.
4. 트랜잭션이 없는 복원력
•
트랜잭션을 사용할 수 없는 경우, 데이터 정리 루틴을 추가하는 등의 행위를 통해 복원력을 만들 수 있다.
5. 예외와 오류
•
예외가 오류라고 주장할 수 있으며 이것이 사실일 수도 있다. 하지만 그렇다고 모든 오류가 예외는 아니다.
3. 디버깅하지 마라
•
디버깅은 항공학에서 항공기 결함을 식별하는 과정에서 사용되던 용어였다.
•
최근 디버깅은 대부분 디버거에서 프로그램을 실행하고 중단점을 두고 코드를 단계별로 추적하며 프로그램의 상태를 조사하는 것을 의미한다.
◦
디버거는 매우 편리하지만 최고의 도구는 아닌데, 문제의 근본적인 원인을 파악하는데 더 시간이 걸릴 수 있기 때문이다.
▪
항상 모든 상황에서 프로그램을 디버깅할 수 있는 것은 아니며 코드가 실행중인 환경에 접근하지 못할 수도 있기 때문이다.
1. printf() 디버깅
•
문제를 찾기 위해 프로그램 내부에 콘솔 출력 라인을 삽입하는 것은 오래된 관행이다.
2. 덤프 다이빙
•
단계별 디버깅을 위한 또 다른 방법은 크래시 덤프를 검사하는 것이다.
◦
크래시 덤프는 프로그램의 메모리 공간의 스냅샷 내용을 담고 있는 파일을 말한다. 유닉스 시스템에선 코어 덤프라고 말하기도 한다.
3. 고무 오리 디버깅
•
이는 책상 위에 앉아있는 고무 오리에게 문제를 말해가며 해결하는 방법이다.
•
문제를 말로 표현하면서 문제를 더 확실하게 재구성하게 되고 마법처럼 문제에 대한 해결책을 찾을 수 있게될 것이다.
4. 요약
•
중요하지 않은 버그를 수정하기 위해 리소스를 낭비하지 않으려면 버그에 우선순위를 정해야 한다.
•
해당 사례에 대해 계획적이고 의도적인 대응 방안이 있는 경우에만 예외를 포착하라. 그렇지 않으면 잡지 마라.
•
충돌을 사후에 방지하는 대신 먼저 충돌을 견딜 수 있는 예외 복원 코드를 작성하라.
•
오류가 일반적이거나 예상되는 경우에는 예외 대신 결과 반환 코드나 enum을 사용하라.
•
투박한 단계별 디버깅보다 더 빠르게 문제를 확인하기 위해 프레임워크에서 제공하는 추적 기능을 사용하라.
•
사용 가능한 다른 방법이 없을 경우 프로덕션에서 실행 중인 코드의 문제를 분석하기 위해 크래쉬 덤프 분석을 사용하라.
•
웹 사이트의 임시 작성글을 고무 오리 디버깅 도구로 사용하고 그동안 무엇을 시도했는지 자문하라.