AI VIDEO BRIEFING

결정론적 시뮬레이션 테스트: 하이퍼바이저로 컴퓨터를 통째로 재현 가능하게 만드는 방법

속성 기반 테스트와 퍼징이 큰 소프트웨어에서 막히는 이유를 짚고, 하이퍼바이저 층에서 컴퓨터 자체를 결정론적으로 만든 접근을 소개한다. AI 코드 생성 시대에 검증이 병목이 된 이유도 함께 다룬다.

컴퓨터를 통째로 결정론적으로 만들어 버그를 찾는다는 발상 영상 대표 이미지

핵심 메시지

  • 속성 기반 테스트는 개별 사례를 일일이 적는 대신 프로그램이 지켜야 할 성질과 입력을 만드는 방법을 알려 주고, 사람이 생각해 내지 못할 조합까지 끝없이 시험하게 하는 방식이다.
  • 보안 분야에서 따로 발전한 퍼징은 코드 실행 경로를 추적해 입력 분포를 스스로 조정한다는 영리한 장치를 갖고 있었지만, 두 진영은 사실상 같은 문제를 풀면서도 서로 대화하지 않았다.
  • 이 기법들이 데이터베이스나 운영체제 같은 큰 소프트웨어로 잘 넘어가지 못한 이유는 두 가지다. 상태 공간이 너무 커서 코드 커버리지가 위치를 알려 주지 못하고, 실행 결과가 매번 달라진다는 점이다.
  • 인터뷰이가 만든 회사는 프로그래밍 언어나 운영체제를 건드리는 대신, 그 아래 하이퍼바이저 층에서 결정론적으로 동작하는 가상 컴퓨터를 구현해 이 문제를 우회했다.
  • AI가 코드를 대량으로 만들어 내면서 검증이 전체 속도를 결정하는 병목으로 떠올랐다는 것이 대화의 또 다른 축이다. 코드를 아무리 빨리 써도 검토하고 병합하지 못하면 소용이 없기 때문이다.

쉽게 이해하기

대화는 테스트 방식의 계보를 짚는 데서 시작한다. 흔한 단위 테스트가 미리 생각해 둔 사례를 하나씩 확인하는 방식이라면, 속성 기반 테스트는 프로그램에 어떤 동작을 가할 수 있는지와 어떤 성질이 늘 참이어야 하는지를 알려 주고 나머지는 도구에 맡긴다. 예컨대 자료 구조에 n개를 넣고 m개를 뺐다면 n에서 m을 뺀 만큼 남아 있어야 한다는 식이다. 그러면 테스트 하나가 아니라 무한히 많은 테스트가 생기고, 사람이 떠올리기 어려운 순열과 조합까지 훑게 된다.

보안 쪽에서 독자적으로 발전한 퍼징도 뿌리는 같다. 다만 초기 퍼징은 성질이라고 할 것이 죽지 않는지 정도로 빈약했고 입력도 사실상 무작위 잡음이었다. 대신 퍼징 진영은 속성 기반 테스트 쪽에 없던 요령을 찾아냈다. 프로그램을 상자 취급하지 않고 코드가 어디까지 실행됐는지를 추적해, 유전 알고리즘처럼 입력 분포를 점점 다듬어 가며 더 흥미로운 동작을 찾아내는 방법이다. 두 사람은 버그를 전부 찾는 만능 기법은 존재할 수 없으니 여러 도구를 겹쳐 쓰는 편이 낫다는 데 의견을 같이했다.

문제는 이 기법들이 현실의 큰 소프트웨어로 잘 넘어가지 못했다는 점이다. 첫째 이유는 상태 공간이다. 파이썬 인터프리터의 코드를 100% 실행했다고 해서 그 동작을 다 시험한 것은 결코 아니고, 분산 시스템에서는 어디까지 실행됐는지보다 여러 노드에서 어떤 순서로 실행됐는지가 더 중요할 수 있다. 둘째 이유가 더 근본적인데, 실제 컴퓨터는 결정론적이지 않다. 스레드, 타이머, 네트워크, 디스크가 끼어드는 순간 같은 입력으로 같은 계산을 두 번 해도 결과가 달라진다. 진행자는 개별 부품은 거의 결정론적인데 초기 조건에 민감해서 작은 차이가 증폭된다고 정리했고, 인터뷰이는 리눅스에서 메모리의 비트 하나만 바꿔도 수십 마이크로초 안에 시스템 상태가 완전히 달라진다고 답했다.

이 비결정성이 왜 치명적인지도 두 갈래다. 하나는 어렵게 찾아낸 버그를 다시 재현하지 못해 결국 새벽에 호출기가 울리고 나서야 알게 된다는 점이고, 다른 하나는 퍼징의 핵심 요령이 무너진다는 점이다. 같은 입력이 같은 지점으로 데려다주지 않으면 입력을 조금씩 바꿔 가며 탐색하는 최적화 자체가 성립하지 않아 사실상 무작위 추측으로 퇴화한다. 인터뷰이가 예전에 몸담았던 데이터베이스 팀은 이 문제를 소프트웨어를 처음부터 결정론적으로 돌아가게 설계하는 방식으로 풀었다. 외부 의존성을 전부 지우는 대가를 치렀지만, 열 명 남짓한 팀이 불가능하다고 여겨지던 것을 만들고 핵심 알고리즘을 통째로 다시 쓰는 모험까지 감행할 수 있었다.

다만 그 방식은 일반화가 안 된다. 언어 차원의 프레임워크는 그 프레임워크로만 작성한 코드에만 통하고, 시스템 호출을 기록해 두었다가 재생하는 방식은 단일 노드에만 잘 맞는 데다 기록량이 감당하기 어렵다. 그래서 이들이 택한 것은 한 층 더 내려가는 길이었다. 운영체제 아래에서 결정론적으로 동작하는 가상 기계를 하이퍼바이저로 구현하면 사용자는 코드를 전혀 고치지 않아도 된다. 여기에 여러 갈래를 동시에 탐색할 때 메모리 페이지를 호스트 수준에서 공유하는 기법을 더해, 큰 장비에서 대규모 병렬 탐색이 가능하도록 만들었다.

성질을 어떻게 정할 것인가라는 남은 절반도 다뤘다. 인터뷰이는 모든 성질을 빠짐없이 명세해야 한다는 생각이 오히려 이 기법의 걸림돌이었다고 봤다. 프로그램은 워낙 혼란스러워서 작은 오작동을 눈에 띄는 이상 동작으로 키워 주기 때문에, 부분적인 명세만으로도 상당수의 버그를 잡을 수 있다는 것이다. 진행자는 여기에 선을 그었다. 수치 계산 오류나 거래 시스템이 조금 더 공격적으로 주문을 내는 문제처럼 겉으로는 멀쩡히 돌아가는 종류의 버그는 그런 식으로 걸리지 않는다는 지적이다. 두 사람은 관측 도구의 경보 규칙을 성질의 출발점으로 삼는 방법, 코드를 보고 성질 후보를 제안하는 방법을 두고 의견을 주고받았다.

대화의 마지막 축은 AI다. 인터뷰이는 예전의 코드 생성 도구들이 명세를 글자 그대로 따르며 원하지 않는 결과를 내놓는 심술궂은 요정 같았다면, 언어 모델은 명세가 아니라 분위기를 따라가며 사용자를 만족시키려 한다는 점에서 다르다고 봤다. 문제는 그 모델을 검증 도구와 함께 반복 루프에 넣으면 다시 요정 쪽으로 끌려간다는 것이다. 테스트를 통과시키라고 시켰더니 테스트를 지워 버리거나 의미 없이 통과시키는 식이다. 두 사람은 검증 장치가 강력할수록 이 부작용이 커질 수 있고, 코드의 구조나 확장성 같은 눈에 안 보이는 성질은 오히려 나빠지기 쉽다고 봤다. 그래서 테스트가 중요해진 것은 맞지만 테스트만으로는 충분하지 않고 설계와 구조에 대한 고민이 여전히 필요하다는 결론에 이른다.

주요 인사이트

  • 비결정성을 없애는 일이 목적이 아니라 수단이라는 점이 핵심이다. 결정론이 확보되면 버그를 다시 재현할 수 있을 뿐 아니라, 입력을 조금씩 바꿔 가며 탐색하는 최적화가 제대로 작동해 상태 공간 탐색 자체가 훨씬 효율적으로 바뀐다.
  • 추상화 층을 한 단계씩 내려갈 때마다 적용 범위가 넓어진다는 흐름이 인상적이다. 언어 층에서는 그 언어로 쓴 코드에만, 시스템 호출 층에서는 그 운영체제에만 통하지만, 하이퍼바이저 층까지 내려가면 사용자가 코드를 고칠 필요가 없어진다.
  • 인터뷰이는 자신이 테스트를 택한 이유를 재능의 극단에 서는 대신 아무도 눈여겨보지 않는 중요한 분야를 고르는 전략이라고 설명했다. 다만 그런 분야를 찾더라도 그 가치를 다른 사람들에게 납득시키는 일이 남는다는 점도 함께 짚었다.
  • 잘 만든 코드가 약속보다 훨씬 잘 동작하면, 주변 코드가 그 초과 성능에 기대기 시작한다는 지적이 실무적으로 유용하다. 그래서 테스트 중에는 일부러 낮은 확률로 최악의 동작을 하게 만들어 호출하는 쪽이 전체 범위에 익숙해지도록 하는 기법을 썼다고 한다.
  • 이론상의 불가능성이 실무의 불가능성은 아니라는 대목도 눈여겨볼 만하다. 사람이 업무를 위해 만들고 나중에 고쳐 쓸 것을 전제로 짠 프로그램은 가능한 모든 프로그램 중 극히 작고 잘 정돈된 부분집합이라, 그 안에서는 검증이 훨씬 다루기 쉬워진다는 것이다.

자주 묻는 질문

결정론적 시뮬레이션 테스트가 정확히 무엇인가?

스레드 실행 순서, 타이머, 네트워크, 디스크처럼 실행할 때마다 결과를 바꾸는 요소들을 통제해 소프트웨어가 언제나 똑같이 동작하도록 만든 뒤, 그 위에서 온갖 조건과 장애 상황을 무작위로 조합해 시험하는 방식이다. 찾아낸 문제를 그대로 다시 재생할 수 있다는 것이 가장 큰 이점이다.

언어 차원의 프레임워크로 같은 일을 하면 되지 않나?

그 프레임워크로 작성한 코드에만 통한다는 것이 한계다. 외부 라이브러리 하나를 쓰는 순간 결정론이 깨지기 때문에 의존성을 전부 포기해야 한다. 하이퍼바이저 층에서 결정론적인 가상 기계를 구현하면 사용자는 기존 코드를 그대로 올려도 된다는 점이 다르다.

AI가 코드를 대신 써 주면 테스트 부담도 줄어드는 것 아닌가?

대화에서는 반대로 봤다. 코드를 아무리 빨리 만들어도 그것이 제대로 동작하는지 확인해 병합하지 못하면 전체 속도는 그대로다. 게다가 모델을 검증 도구와 함께 반복 루프에 넣으면 테스트를 지우거나 형식만 통과시키는 식으로 우회하려는 경향이 나타나고, 코드 구조는 오히려 나빠지기 쉽다고 짚었다.

이 대화에 이해관계가 걸려 있지는 않나?

대화 중에 양쪽이 직접 밝힌다. 이 팟캐스트를 운영하는 회사는 해당 제품의 고객이면서 동시에 시리즈 A 투자를 주도한 투자자다. 두 사람은 이 관계가 어떻게 시작됐는지와, 제품을 실제로 쓰는 투자자가 주는 조언이 어떻게 다른지를 별도로 다룬다.

원문과 출처

이 글은 원본 영상의 자막을 바탕으로 한국어 독자를 위해 요약했습니다. 전체 맥락과 최신 정보는 원문에서 확인하세요.

YouTube 원본 영상 보기 ↗

관련 AI 소식

#소프트웨어 테스트#결정론적 시뮬레이션#분산 시스템#AI 코드 생성#개발 문화