규제 판단을 소프트웨어로 옮기며 배운 것: Q-Atelier 엔진 설계 기록
규제 요건을 규칙으로 코드화할 때 실제로 부딪힌 문제들. 판단의 재현성, 규칙의 버전 관리, 전문가 보정을 엔진 밖에 두는 설계를 직접 만든 시스템의 기록으로 정리한다.
판단이 사람 머릿속에만 있으면 확장되지 않는다
의료기기 인허가 실무에서 가장 자주 나오는 질문은 "이 변경, 허가 다시 받아야 하나요?" 다. 원료를 바꿨을 때, 치수를 조정했을 때, 소프트웨어를 패치했을 때. 답은 매번 다르고, 그 답을 아는 사람은 대개 조직에 한두 명이다.
문제는 그 판단이 문서로 남지 않는다는 데 있다. 담당자가 자리를 비우면 같은 질문에 다른 답이 나오고, 심사에서 "왜 그렇게 판단했느냐"는 질문을 받으면 근거를 다시 구성해야 한다. 판단의 품질이 사람에 묶여 있는 한, 조직이 커져도 규제 대응 역량은 함께 크지 않는다.
Q-Atelier 는 이 판단을 소프트웨어로 옮기려고 만들었다. 처음에는 데스크탑 프로그램이었고, 지금은 클라우드로 옮겨 여러 조직이 각자의 데이터로 쓰는 형태가 됐다. 아래는 그 과정에서 내린 설계 결정과, 그렇게 결정한 이유의 기록이다.
규칙을 «코드»가 아니라 «데이터»로 둔다
가장 먼저 정한 것은 규칙을 조건문으로 짜지 않는다는 원칙이다.
규제 판단을 if 문으로 구현하면 규칙 하나를 바꿀 때마다 코드를 고쳐야 한다. 코드를 고치면 배포가 필요하고, 배포가 필요하면 규제 개정을 따라가는 속도가 개발 일정에 묶인다. 무엇보다 어떤 규칙이 적용됐는지 사람이 읽을 수 없다.
그래서 규칙은 데이터로 분리했다. 위험도 매핑, 영향 영역, 판단 근거가 각각 데이터 구조로 존재하고, 엔진은 그 데이터를 «해석»할 뿐이다. 규칙을 보강할 때 손대는 것은 데이터이고, 엔진 코드는 그대로다.
여기에 규칙셋 버전을 붙였다. 판단 결과에는 그 판단을 내린 규칙셋의 버전이 함께 남는다. 규제는 개정되고 규칙도 따라 바뀌는데, 버전이 없으면 과거의 판단이 왜 지금과 다른지 설명할 수 없다. 버전이 있으면 "이 판단은 그 시점 규칙으로 내려졌다"고 말할 수 있고, 필요하면 새 규칙으로 다시 돌려 차이를 비교할 수 있다.
판단 엔진은 순수 함수여야 한다
엔진은 데이터베이스도 네트워크도 호출하지 않는 순수 함수로 만들었다. 입력을 넣으면 출력이 나오고, 같은 입력에는 언제나 같은 출력이 나온다.
이 제약을 스스로에게 건 이유는 두 가지다.
첫째, 재현 가능해야 한다. 심사에서 판단 근거를 요구받았을 때 "그때 시스템이 이렇게 답했다"가 아니라 "지금 같은 입력을 넣으면 같은 답이 나온다"고 보여줄 수 있어야 한다. 엔진이 실행 시점의 DB 상태에 의존하면 이게 성립하지 않는다.
둘째, 테스트할 수 있어야 한다. 규제 판단은 틀리면 대가가 큰데, 눈으로 확인하는 검증은 규칙이 늘어날수록 무너진다. 순수 함수라면 입력과 출력 쌍을 쌓아 자동으로 검증할 수 있다.
판단 로직 자체도 단계로 나눴다. 기본 위험도를 정하고, 조합에 따라 상향하고, 개발 부서가 표시한 영향을 반영하고, 그 결과로 필요한 문서와 시험을 산출하고, 마지막에 주의가 필요한 지점을 경고로 붙인다. 각 단계가 분리돼 있어 어느 단계에서 판단이 갈렸는지 되짚을 수 있다.
규칙이 바뀌면 «티가 나야» 한다
규칙을 데이터로 두면 좋은 점이 많지만, 위험이 하나 생긴다. 데이터를 고쳤을 때 의도하지 않은 곳의 판단까지 조용히 바뀌는 것.
규제 판단에서 이건 특히 위험하다. 화면에 에러가 나지 않고, 로그도 남지 않고, 그냥 어느 날부터 다른 답이 나온다. 쓰는 사람은 알아차릴 방법이 없다.
그래서 엔진 출력에 골든 스냅샷을 걸었다. 대표 입력들에 대한 현재 출력을 통째로 동결해 두고, 규칙을 손댄 뒤 같은 테스트를 돌려 하나라도 달라지면 실패하게 했다.
이 안전망이 실제로 필요했던 순간은 판단 로직을 «규칙을 데이터로 두는» 구조로 옮길 때였다. 내부 구조를 통째로 바꾸면서도 출력은 100% 같아야 했는데, 그 판단 결과를 쓰는 화면과 문서가 여럿이라 어느 하나가 조용히 어긋나면 찾기가 어렵다. 스냅샷을 먼저 동결해 두고 리팩터링한 덕분에, 구조를 바꾸면서도 "판단은 그대로"임을 매번 확인할 수 있었다.
원칙은 단순하다. 규칙을 «의도적으로» 바꿀 때만 스냅샷을 갱신한다. 그 외의 변화는 전부 사고다.
판단 로직은 서버 밖으로 나가면 안 된다
규칙셋은 그 자체가 자산이다. 브라우저로 내려가는 순간 누구나 열어볼 수 있다.
그래서 판단 모듈에는 서버 전용 표식을 달아 두었다. 실수로라도 클라이언트 번들에 포함되면 빌드가 실패한다. 사람이 규칙을 지키는 대신, 규칙을 어기면 빌드가 깨지게 만든 것이다.
경험상 "조심하자"는 약속은 시간이 지나면 반드시 새어 나간다. 지켜야 할 경계가 있다면 어겼을 때 자동으로 실패하는 장치를 함께 두는 편이 낫다.
사람의 판단은 엔진 «바깥»에 둔다
엔진을 만들면서 가장 오래 고민한 지점이다.
전문가가 엔진의 판단에 동의하지 않는 경우는 반드시 생긴다. 규칙이 아직 다루지 못하는 제품이거나, 같은 변경이라도 맥락에 따라 달리 봐야 하는 경우다. 이때 엔진의 규칙을 직접 고치면 두 가지가 무너진다. 하나는 재현성이다. 과거 판단을 다시 돌릴 수 없게 된다. 다른 하나는 추적성이다. 그 판단이 규칙 때문인지 사람의 개입 때문인지 구분할 수 없게 된다.
그래서 보정(calibration)을 엔진 바깥에 뒀다. 순수 함수인 엔진은 그대로 두고, 그 앞뒤를 감싸는 층에서 전문가가 등록한 보정을 적용한다. 보정은 판단을 뒤엎는 게 아니라 조정한다. 특정 조건에서 위험도를 한 단계 올리거나 내리는 식이다.
핵심은 무엇이 적용됐는지가 결과에 남는다는 점이다. 판단 결과를 열면 엔진이 낸 답과 그 위에 어떤 보정이 얹혔는지가 함께 보인다. 나중에 "이 판단은 왜 이렇게 나왔나"를 물으면, 규칙 때문인지 사람의 보정 때문인지 구분해 답할 수 있다.
이 구조 덕분에 엔진은 순수 함수로 남고, 사람의 개입은 기록으로 남는다. 둘 다 포기하지 않는 방법을 찾는 데 시간이 꽤 걸렸다.
되돌릴 수 있는 단위로 쌓기
스키마는 계속 바뀐다. 규제 요건이 늘고, 화면이 늘고, 처음에 잘못 잡은 구조가 드러난다.
그래서 데이터베이스 변경은 한 번에 하나씩, 되돌릴 수 있는 단위로 쌓았다. 지금까지 쌓인 변경 이력은 수백 건이고, 그 각각이 "언제 무엇을 왜 바꿨는지"의 기록이다. 규모 자체보다 중요한 건 이게 한 번에 만들어지지 않았다는 사실이다. 구조를 수백 번 고쳤고, 매번 되돌릴 수 있는 형태로 남겼다.
규제 시스템에서 이 습관은 선택이 아니다. 심사에서 "이 데이터가 언제부터 이렇게 관리됐느냐"는 질문을 받으면, 그 답이 이력에 남아 있어야 한다.
아직 사람이 필요한 자리
엔진은 규칙이 다루는 범위 안에서만 정확하다. 규칙 바깥의 판단, 곧 전례가 없는 제품이나 심사관과의 협의가 필요한 경계 사례, 임상 설계는 여전히 사람의 몫이다.
그래서 Q-Atelier 는 엔진이 산출하고 전문가가 교차검증하는 구조로 운영한다. 엔진이 사람을 대체하는 게 아니라, 사람이 매번 처음부터 판단하지 않아도 되게 만드는 것이 목표다.
이 글은 자랑이 아니라 기록이다. 우리가 규제 판단을 소프트웨어로 옮기며 부딪힌 문제들은, 같은 일을 하려는 조직이라면 대체로 똑같이 부딪힌다. 판단을 데이터로 분리할 것인가, 재현 가능하게 만들 것인가, 바뀌었을 때 알아차릴 장치를 둘 것인가, 사람의 개입을 어디에 둘 것인가. 이 결정들은 기능을 만들기 전에 내려야 하고, 나중에 되돌리기가 가장 어렵다.
조직에 맞는 규제 시스템을 검토하고 계시다면, Q-Atelier Bespoke에서 어떤 순서로 진행하는지 정리해 두었다.