1. 소프트웨어 결함의 두 가지 범주: 부작위와 작위
Joel Drapper는 소프트웨어에서 발생하는 버그를 그 동작 양상에 따라 ‘부작위의 버그(Bugs of Omission)’와 ‘작위의 버그(Bugs of Commission)’로 명확히 구분합니다. 이 구분은 단순히 오류의 종류를 나누는 것을 넘어, 시스템의 안정성과 신뢰성을 어떻게 관리할 것인가에 대한 철학적 기초를 제공합니다.
부작위의 버그 (Bugs of Omission)
부작위의 버그는 소프트웨어가 특정 작업을 수행하기를 거부하거나 멈추는 상태를 말합니다. 대표적으로 예외(Exception) 발생, 프로그램 충돌(Crash), 혹은 무반응 상태 등이 여기에 포함됩니다. 이러한 버그의 가장 큰 장점은 ‘가시성’입니다. 문제가 발생한 즉시 시스템이 멈추기 때문에 개발자는 오류를 즉각적으로 인지할 수 있으며, 스택 트레이스 등을 통해 문제의 원인을 파악하기가 매우 수월합니다. 또한, 오류 발생 시점에서 실행이 중단되므로 잘못된 데이터가 시스템 전체로 확산되는 것을 원천 차단할 수 있습니다.
작위의 버그 (Bugs of Commission)
반면 작위의 버그는 시스템이 겉으로는 아무런 문제 없이 작동하는 것처럼 보이지만, 실제로는 ‘잘못된’ 동작을 수행하는 상태를 의미합니다. 이는 매우 위험한 형태의 결함인데, 소프트웨어가 조용히 데이터를 오염시키거나, 삭제해서는 안 될 중요한 레코드를 삭제하고, 의도하지 않은 이메일 발송이나 결제 처리를 수행하기 때문입니다. 이러한 버그는 ‘침묵’ 속에서 진행되므로 발견하기가 매우 어렵고, 문제가 발견되었을 때는 이미 되돌릴 수 없는 막대한 피해가 발생한 이후인 경우가 많습니다.
2. 왜 실패하는 코드가 더 안전한가?
많은 개발자들은 런타임 에러나 시스템 중단을 피해야 할 최악의 상황으로 간주합니다. 하지만 Drapper는 작위의 버그와 비교했을 때 부작위의 버그가 전략적으로 훨씬 우월하다고 주장합니다. 부작위의 버그는 그 영향력이 ‘제한적(Bounded)’이고 ‘예측 가능(Predictable)’합니다. 시스템이 멈추면 서비스는 일시 중단되지만, 데이터의 무결성은 보존됩니다. 반면 작위의 버그는 그 영향력이 무한하며 파괴적일 수 있습니다. 잘못된 로직으로 인해 고객에게 수천 통의 스팸 메일이 발송되거나 잘못된 금액이 인출되는 상황은 단순한 시스템 중단보다 훨씬 심각한 비즈니스 위기를 초래합니다.
3. 런타임 어설션(Runtime Assertions)의 전략적 가치
모든 소프트웨어 시나리오를 사전에(Ahead of time) 테스트하는 것은 불가능에 가깝습니다. 운영 환경의 복잡성은 개발 환경의 테스트 케이스를 언제나 뛰어넘기 때문입니다. 이에 대한 실질적인 대안으로 제시되는 것이 바로 ‘런타임 어설션’입니다. 런타임 어설션은 프로그램이 실행되는 도중(Just in time) 특정 조건이 유효한지 검증하는 장치입니다. 만약 데이터가 예상 범위를 벗어나거나 상태가 비정상적이라면, 어설션은 즉시 예외를 발생시켜 시스템을 중단시킵니다. 이는 잠재적인 작위의 버그를 강제로 부작위의 버그로 전환하는 역할을 수행하며, 시스템이 잘못된 길로 들어서기 전에 안전하게 멈추도록 보장합니다.
4. 결론: 방어적 설계의 중요성
결국 소프트웨어의 신뢰성은 버그가 아예 없는 상태를 만드는 것이 아니라, 버그가 발생했을 때 시스템이 얼마나 안전하게 반응하느냐에 달려 있습니다. 개발자는 실패를 두려워하지 말고, 오히려 ‘안전하게 실패하는(Fail-safe)’ 구조를 설계해야 합니다. 런타임 어설션을 코드 곳곳에 배치하여 데이터의 무결성을 실시간으로 감시하고, 이상 징후가 발견될 경우 즉시 실행을 중단하는 방어적 태도는 현대 소프트웨어 개발에서 반드시 갖춰야 할 핵심 역량입니다.