코드는 왜, 어떻게 실패하는가 - SFTA

by 현우민

현대 기술 환경에서 소프트웨어는 더 이상 하드웨어의 조용한 조력자가 아니다. 이제는 복잡한 시스템의 심장부에서 정보를 순환시키고 논리를 유지하는 중심 역할을 맡는다. 흥미로운 점은, 이 심장은 금속처럼 마모되지도, 부품처럼 부식되지도 않음에도 불구하고 예기치 않은 순간에 멈출 수 있다는 사실이다. 물리적 부품의 고장은 감각적으로 포착되고 점진적으로 다가오지만, 소프트웨어의 문제는 논리 구조, 인간의 해석, 그리고 수많은 상호작용의 복잡성에서 비롯된다. 결국 오류는 코드의 노후가 아니라 인간이 만든 논리적 틈, 시간의 흐름 속에서 교차하는 조건들의 미세한 어긋남에서 발생한다. 그래서 소프트웨어 장애는 재현되지 않을 수 있고, 특정 순간에만 모습을 드러내며, 때로는 한 번뿐인 ‘유령 같은 현상’으로 남는다.


이처럼 소프트웨어가 시스템의 중심을 차지하는 시대에는 “고장이 난다”라는 개념의 범위 역시 확장된다. 금속이 닳고, 베어링이 마모되고, 회로가 끊어지는 전통적 세계에서도 사고는 일어난다. 그러나 같은 수준의 위험이 보이지 않는 코드—즉 논리의 세계—에서도 나타난다는 점이 현대 시스템을 훨씬 더 복잡하게 만든다. 이 투명하지 않은 실패는 형태가 없어서 감지하기 어렵고, 물리적 장비처럼 손으로 만져볼 수도 없다. 그렇기 때문에, 이러한 실패를 분석하기 위한 체계적인 접근이 필수적이며, 그 대표적인 도구가 바로 소프트웨어 고장 분석 기법인 Software Fault Tree Analysis(SFTA)다. SFTA는 소프트웨어가 어떻게, 어떤 조건 아래서 실패할 수 있는지를 추적하며, 현대 시스템이 안고 있는 보이지 않는 위험의 구조를 드러내는 중요한 분석 방식으로 자리 잡고 있다.


SFTA란 무엇인가 — 소프트웨어도 실패한다


사고라는 큰 사건을 최상위에 두고, 그 아래로 원인들이 뻗어 나가며 나무 형태를 이루는 방식이다. 자동차 사고를 예로 들면 엔진 과열, 브레이크 오류, 타이어 손상 같은 가지들이 생기고, 어떤 원인이 단독으로 사고를 유발하는지(OR), 혹은 여러 조건이 동시에 충족되어야 사고가 발생하는지(AND)를 분석한다.


전통적인 FTA(Fault Tree Analysis)는 흔히 AND 게이트와 OR 게이트로 이루어져 한 사건이 발생할 조건과 그 확률을 분석한다.


그러나 이러한 설명은 수학이나 공학에 익숙하지 않은 사람에게는 다소 추상적으로 들릴 수 있다. 그래서 흔히 FTA를 “사고의 원인을 가지처럼 그려 나가는 방식”으로 설명한다.


어떤 사고의 원인을 조건별로 나열하다 보면 가지가 퍼지며 거꾸로 세운 나무 형태를 이루는데, 그래서 이름이 Fault Tree다.


예를 들어 “자동차 사고”라는 최상위 사건을 두고, 그 아래로 엔진 과열, 브레이크 오류, 타이어 손상 등 다양한 원인이 가지처럼 뻗어 나가며 나무 형태를 이룰 수 있다. 그리고 우리는 각 원인이 동시에 충족되어야 사고가 나는지(AND), 혹은 둘 중 하나만 단독으로 발생해도 사고로 이어지는지(OR)를 판단하게 된다. FTA는 이런 사건들을 독립적으로 바라보며 구조를 만든다.


이러한 사건들은 전형적인 하드웨어 사고 모델이다.


하지만 현실은 조금 달라졌다. AI가 코드를 만들고, 자동차는 센서를 통해 수집한 데이터를 소프트웨어로 처리하며 움직인다. 그러면 이런 질문이 바로 나온다.

코드는 낡지도 않았는데 왜 실패할까?
한 번 잘 돌아가던 기능이 어느 순간 갑자기 왜 오작동할까?
어떨 때 소프트웨어는 시스템 전체를 위험하게 만드는가?


소프트웨어의 실패 원인은 물리적 마모와 다르다. 대표적으로 다음과 같은 오류가 있다.

논리 오류(Logic Error): if 조건 하나만 잘못 작성해도 전체 알고리즘이 틀어진다.

경계 조건 오류(Boundary Issues): 0으로 나누기, 잘못된 배열 인덱스, 오버플로우 등.

타이밍 문제(Timing Faults): 스레드 간 경합, 메시지 지연, 동기화 실패.

요구사항 해석 오류(Requirement Misinterpretation): 코드가 “정확히 다른 것”을 충실히 구현했을 때.

인터페이스 오류(Interface Faults): 다른 시스템에서 보내오는 데이터 형식이 달라졌을 때.

환경 의존 오류(Environmental Faults): OS 업데이트, 라이브러리 버전 차이로 인해 기능이 깨질 때.

이처럼 소프트웨어가 실패하는 방식은 물리적 고장과 완전히 다르다. 그래서 소프트웨어에 특화된 결함 나무 분석, 즉 SFTA는 일반 FTA와는 다르게 결과를 향해 달려간다.


왜 SFTA가 필요한가

소프트웨어의 위험성은 결국 극도로 작은 원인인 ‘한 줄의 코드'가 전체 시스템을 무너뜨릴 수 있다는 비대칭성 사실에서 비롯된다. 전통적 하드웨어 시스템은 고장이 점진적으로 마모되고, 고장의 징후가 감각적으로 드러나지만, 소프트웨어는 겉으로는 아무 문제가 없어 보인다. 심지어 문제를 유발한 코드가 십수 년 동안 조용히 정상 동작하다가 아주 제한된 입력 조합이나 특수한 시간 조건이 맞물리는 특정한 상황이 겹칠 때 갑자기 실패를 일으키기도 한다. 그러므로 소프트웨어 실패는 단순히 “코드 한 줄이 틀렸다”는 문제를 넘어, 시스템 전체의 시간·상태·의미가 특정 구조로 결합될 때 나타나는 조건적 사건에 가깝다. 다시 말해, 소프트웨어 실패는 물리적 파손이 아니라 구조적 가능성이 현실화된 결과이며, 철학적 의미에서 ‘세계가 특정 방식으로 배열되었기 때문에 발생하는 현상’이라고도 볼 수 있다.


이 관점에서 볼 때 소프트웨어 오류는 결국 의도와 결과의 어긋남이라는 더 깊은 문제를 드러낸다. 사람은 요구사항을 해석할 때 언어적·논리적 약점을 가지고 있으며, 그 약점이 코드에 고스란히 반영된다. 요구를 오해한 채 정확하게 ‘잘못된 기능’을 구현하는 경우도 있고, 서로 다른 시스템이 동일한 데이터를 서로 다르게 해석해 오류가 발생하는 경우도 흔하다. 이는 단순 기능 구현이 안전을 보장하지 않음을 의미한다. 오히려 중요한 것은 각 모듈이 같은 세계관과 의미 체계 속에서 동작하느냐 하는 문제이다. 결국 소프트웨어 시스템의 오류는 논리·의미·해석의 균열에서 비롯되며, 이는 기술을 넘어 인간 인지의 한계를 반영한다.


이 때문에 SFTA는 단순한 오류 분석을 넘어, 시스템 전체에서 의미의 흐름을 점검하는 철학적 도구라고 할 수 있다. 소프트웨어가 실패하는 방식은 인간의 사고방식이 오류를 포함하는 방식과 닮아 있으며, SFTA는 그 오류를 드러내는 과정이다.


따라서 SFTA는 단순히 버그를 찾는 절차가 아니라, 시스템 전체에서 의미가 흐르는 방식을 점검하는 철학적 분석 도구로 볼 수 있다. 소프트웨어가 실패하는 방식은 인간이 사고할 때 실수를 범하는 방식과 닮아 있다. 조건을 잘못 연결하고, 의미를 다르게 해석하고, 비정상적인 순서를 우연히 만들어내는 그 구조적 오류를 SFTA는 논리적 가지를 통해 드러낸다. 즉, SFTA는 “어떤 조건들이 어떤 의미로 결합될 때 실패가 가능해지는가”를 밝혀내는 과정이며, 이는 형태는 기술 도구지만 실질적으로는 ‘내재된 가능성의 해석학’에 가깝다.


하드웨어 고장이 눈에 잘 보이고 통계적으로 다루기 쉬운 것과 달리, 소프트웨어는 다음과 같은 이유로 훨씬 위험하고 다루기 어렵다. 첫째, 고장이 재현되지 않을 수 있다. 특정 입력 조합에서만 나타나거나, 수백만 번 중 한 번 발생하는 오류도 있다. 둘째, 시간과 상태에 따라 결과가 달라진다. 물리적 장치는 같은 조건에서 같은 결과를 내지만, 소프트웨어는 상태 머신처럼 상황마다 완전히 다른 흐름을 타기도 한다. 셋째, 인터페이스 복잡성이 증가할수록 오류는 기하급수적으로 늘어난다. 서로 다른 시스템이 동일한 데이터를 다르게 해석하면 사고는 금방 현실화된다. 넷째, 업데이트는 결함을 고치기도 하지만 동시에 새로운 결함을 만들어낸다. 보완한다고 해서 안정성을 확신할 수 없고, ‘고쳐지지 않던 문제’가 갑자기 모습을 드러내기도 한다.


이런 이유 때문에 현대 시스템에서 사고의 기원은 하드웨어보다 연결된 소프트웨어의 오작동에서 더 자주 발생한다. 시스템이 복잡해질수록 어떤 조건이 결합될 때 실패가 가능해지는지를 사전에 구조적으로 파악하는 일이 필수적이며, 단순한 버그 추적만으로는 결코 충분하지 않다. 그래서 등장한 도구가 바로 SFTA다. SFTA는 사고로 이어질 수 있는 소프트웨어적 조건을 하나하나 논리 구조로 드러내어, 보이지 않는 위험의 가능성을 체계적으로 탐색하는 분석 방식이다.



SFTA는 기존 FTA와 어떻게 다른가

FTA와 SFTA는 같은 ‘나무 구조’를 사용하지만, 그 뿌리와 토양은 완전히 다르다. FTA는 하드웨어 기반 사고 분석에 기초한다. 물리 세계의 고장은 확률과 물리적 속성으로 설명할 수 있으며, 재현성이 높고, 시간에 따른 변화가 비교적 명확하다. 그러나 소프트웨어는 물리적 제약을 거의 받지 않으며, 논리적 조건과 시간적 순서, 입력의 조합에 따라 매우 다른 결과를 낸다.


또한 소프트웨어 오류는 종종 인간의 인지 한계를 반영한다. 하드웨어의 고장이 “물질의 한계”라면, 소프트웨어의 고장은 “개념적 한계”다. 알고리즘이 복잡해질수록 인간은 그 전체를 동시에 이해하기 어렵고, 각 모듈 간 관계가 늘어날수록 시스템은 예측 불가능한 상태로 변한다. 이는 철학적으로 “복잡성의 문제”이며, SFTA는 이 복잡성 속에서 위험을 줄이기 위한 구조적 해석 장치로 기능한다.

구분: 실패의 본질
FTA (전통적): 물리적 고장
SFTA (소프트웨어 특화): 논리적·의사결정적 오류
구분: 고장 발생 방식
FTA (전통적): 점진적, 마모, 단선
SFTA (소프트웨어 특화): 조건 조합, 경로 선택 오류
구분: 재현성
FTA (전통적): 비교적 높음
SFTA (소프트웨어 특화): 매우 낮을 수 있음
구분: 원인 분석 단위
FTA (전통적): 하드웨어 부품
SFTA (소프트웨어 특화): 함수, 조건문, 변수 흐름
구분: 위험 증가 요인
FTA (전통적): 노후화
SFTA (소프트웨어 특화): 복잡도, 인터페이스, 시간 흐름

FTA가 원래는 하드웨어 안전을 다루도록 설계되었기 때문에 물리적 원인을 좁혀 가는 것이라면, SFTA는 '추상적 오류를 충분히 표현하기 어렵다'는 약점을 보완하여 논리 구조 논리적 공간에서 가능한 모든 의미적 경로를 탐색하는 과정이다. 말하자면 FTA가 ‘현상’을 다룬다면 SFTA는 ‘가능성’을 다룬다. 사고는 언제나 가능성 속에서 발생하기 때문이다.


SFTA 절차와 단계 — 어떻게 분석하는가

SFTA의 과정은 단순한 기술 절차가 아니라, 사고의 가능성이 비롯되는 논리적 조건들을 하나하나 밝혀 나가는 탐색이다. 먼저 최상위 사건을 정의한다. 예를 들어 “자율주행 차량이 보행자를 인식하지 못함”이라는 사건을 설정한다. 이 최상위 사건은 하나의 결론처럼 보이지만, 실제로는 수많은 조건과 흐름이 얽혀 만들어진 결과다.


다음으로, 이 사건과 관련된 소프트웨어 기능을 규명한다. 센서 데이터를 처리하는 단계, 객체 인식 모델, 신뢰도 평가, 인터페이스 모듈 등이 모두 분석 범주에 들어간다. 이 과정은 철학적으로 보면 ‘현상 뒤에 있는 원인들의 층위를 나누는 작업’이다. 보이지 않는 메커니즘 속 구조를 드러내는 과정이다.


그다음에는 사건이 일어날 수 있는 소프트웨어적 조건들을 체계적으로 나열한다. 예컨대 데이터가 지연되거나, 임계값이 잘못 설정되거나, 특정 포맷이 바뀌었지만 검증 과정이 누락된 경우 등이다. 이런 조건들은 물리적 세계가 아니라 논리적 세계의 ‘사건’이므로, 각각은 독립적이고 추상적이다.

이후 AND와 OR 게이트로 조건들을 결합하며 나무를 내려간다. 이 단계는 마치 철학자가 가능성의 구조를 분석하는 것과 유사하다. 어떤 조건은 단독으로 실패를 유발하지만, 어떤 조건은 함께 발생해야만 사고로 이어진다. 이 논리적 조합의 탐색이 바로 SFTA의 핵심이다.


마지막으로 각 조건이 왜 발생하는지 계속 질문하며 기본 이벤트까지 분해한다. 스레드 우선순위 문제인지, 요구사항 오독인지, 인터페이스 관리 실패인지 등을 파악하는 과정이다. 이 작업은 하나의 오류가 아니라 오류를 만들어낸 인과의 체계를 이해하려는 시도다.


여기서 중요한 철학적 관점은 “실패는 결과가 아니라 과정의 총합”이라는 점이다. SFTA는 실패의 구조를 밝히는 과정이며, 사고가 ‘발생한다’는 사실보다 ‘어떻게 가능해지는가’를 분석한다. 이 가능성의 구조를 조명하는 것이 진정한 안전 분석이다.


Note.


정리를 하면, SFTA는 보통 다음 절차로 수행된다.


1) 최상위 이벤트 정의

예: “자율주행 차량이 보행자를 인식하지 못함”


2) 소프트웨어 기능 범위 설정

객체 인식 알고리즘

센서 데이터 처리

신뢰도 검증 계층

인터페이스 모듈


3) 실패 조건 도출

입력 데이터 값이 비정상

모델이 ‘확신(confidence)’을 지나치게 낮게 판단

시간 지연으로 최신 프레임을 사용하지 못함

외부 시스템이 보낸 메시지 포맷 변경

예외 처리가 없어 무음 실패(silent failure) 발생


4) 논리 구조(AND/OR 게이트)로 조건 결합

예를 들어,

센서 데이터가 늦게 들어옴(Condition A)

예측 모델이 오래된 데이터를 그대로 사용함(Condition B)

→ 두 조건이 동시에 발생해야 사고가 된다면 AND 게이트로 묶는다.

반면,

객체 탐지 모델 충돌(Crash)

탐지 임계값이 잘못 설정됨

→ 둘 중 하나만 발생해도 실패하면 OR 게이트로 표현한다.


5) 기본 이벤트(leaf)까지 분해

각 조건이 “왜 발생하는지”를 질문하며 계속 내려간다.

예:

타이밍 지연 → 스레드 우선순위 설정 오류

임계값 오류 → 요구사항 문서 해석 오류

메시지 형식 불일치 → 인터페이스 버전 관리 실패


6) 검증 및 보정

실제 소스 코드와 맞는지 확인

테스트 결과와 비교

시나리오별 재현 가능성 점검


7) 안전 대책 수립

예외 처리 강화

타이밍 모니터링

인터페이스 검증 계층 추가

단위 테스트·정적 분석 확대

요구사항 리뷰 강화


SFTA는 자율주행 차량, 의료기기, 항공기 임베디드 시스템, 금융 거래 시스템, 산업 제어 시스템 등 복잡한 인터페이스와 논리적 흐름이 존재하는 모든 곳에서 단순히 “버그를 찾는 것”이 아니라 사고로 이어질 수 있는 논리적 조건을 설계 단계에서 제거하는 것이다. 이 적용 범위는 단순히 실용성을 넘어서, 현대 사회가 ‘코드 위에서’ 돌아간다는 사실을 상기시킨다. 소프트웨어는 이제 세계의 구조 그 자체와 닮아 있고, 오류는 곧 세계의 결함과 같은 의미를 갖는다.


따라서 SFTA는 단순한 기술적 작업이 아니라, 인간이 만든 논리적 세계를 안전하게 유지하기 위한 윤리적·철학적 노력이기도 하다. 우리가 설계한 세계가 예측 가능한 방식으로 움직이도록 하기 위한, 하나의 지적 시스템이라 할 수 있다.



결론 — 시스템 안전은 ‘소프트웨어를 이해하는 것’에서 시작된다

현대 시스템의 실패는 하드웨어보다 소프트웨어의 논리적 오해와 의사결정 오류에서 더 자주 발생한다. 눈에 보이지 않는 조건들이 조용히 결합되고, 서로 다른 모듈이 뜻하지 않게 엇갈리며, 판단조건 한 줄의 판단 오류가 수억 원짜리 장비를 멈추고, 작은 업데이트가 전체 시스템의 타이밍을 무너뜨린다. 이때 SFTA는 그 오류의 가능성을 밝혀내는 도구이며, 시스템 안전은 바로 이런 보이지 않는 세계를 이해하려는 시도에서 시작된다.


SFTA는 인간이 만든 인공적 세계의 인과 구조를 드러내는 작업이다. 안전이란 단순히 사고를 막는 행위가 아니라, 우리 자신이 만든 논리적 구조에 책임을 지는 과정이다. 코드와 시스템이 복잡해질수록, 이런 분석은 기술적 필요를 넘어 윤리적 선택에 가까워진다.


결국, 소프트웨어 안전은 기술의 문제가 아니라 세계를 바라보는 방식의 문제다. 시스템을 이해한다는 것은 곧, 우리가 만든 세계의 가능성과 위험을 이해하는 일이다. 그리고 SFTA는 그 세계를 명료하게 바라보게 하는 가장 구조적이고 깊이 있는 도구 중 하나다.

화, 목 연재
이전 23화카카오톡 대규모 업데이트 실패를 바라보며 — SFMEA