2026. 04. 27. · CK · 본문 보강 2026. 09. 08.

범주론을 시스템 설계에 가져오기: 합성·정보 손실·호환성의 경계

읽기 전 요약

범주론은 시스템의 변환과 합성을 생각하는 언어를 제공하지만, 연결선을 그리는 것만으로 호환성과 안정성을 보장하지는 않는다. 문서 변환 예시로 합성 조건, 동형과 정보 손실을 구분하고 요네다 보조정리를 과장해서 적용하지 않는 기준을 정리했다. 수학 정리의 실무 적용을 주장하기 전에 작은 인터페이스부터 점검하려는 개발자를 위한 입문 메모다.

서로 다른 도구를 연결할 때 화면에는 상자와 화살표 몇 개만 남는다. 원고를 읽고, 형식을 바꾸고, 저장한 뒤 보여 준다. 실제 문제는 그 사이에서 생긴다. 날짜가 다른 시간대로 해석되거나, 없는 값과 빈 문자열이 섞이거나, 표시용 요약만 남아 원문을 복원하지 못한다.

범주론을 시스템 설계와 연결해 읽을 때도 이런 작은 변환부터 보려고 한다. 이 글은 범주론으로 운영 시스템의 문제를 해결했다는 후기가 아니다. 합성과 정보 보존을 설명하는 학습 메모이며, 문서 데이터 예시는 이해를 돕기 위해 만들었다. 책 한 권의 내용을 요약하기보다 실무에서 가져올 질문과 가져오면 안 되는 결론을 구분한다.

화살표를 연결하려면 입력과 출력의 뜻이 맞아야 한다

범주는 객체와 그 사이의 사상, 사상의 합성과 항등사상으로 설명한다. 합성은 결합법칙과 항등법칙을 만족해야 한다. 프로그래밍을 처음 연결해 볼 때에는 집합과 전체 함수라는 단순한 예가 편하다. 모든 코드가 자동으로 이 단순한 수학 모형에 들어간다는 뜻은 아니다. 예외나 상태 변경은 따로 다뤄야 한다. Bartosz Milewski의 함수 합성 설명

설명용으로 유효한 원고를 Post, 화면에 표시할 자료를 Card, 문자열을 Text라고 하자. toCard: Post → Cardrender: Card → Text가 있으면 render(toCard(post))를 생각할 수 있다. 앞의 출력이 뒤의 입력에 맞기 때문에 합성이 가능하다. ‘Notion에서 Vercel로 연결한다’보다 각 단계의 데이터 계약이 조금 더 드러난다.

타입 이름이 같다고 의미까지 맞는 것은 아니다. 어떤 시스템의 날짜는 UTC 시각이고 다른 시스템의 날짜는 한국 기준 발행일일 수 있다. 둘 다 문자열이어도 바로 넘기면 안 된다. 허용 형식, 누락값, 시간대와 변환 규칙을 함께 정의해야 한다. 화살표에는 데이터 타입뿐 아니라 이 계약을 붙이는 편이 좋다.

유효하지 않은 입력도 모델 밖으로 밀어내지 않는다. 변환 함수가 언제나 Post를 돌려준다고 적고 실제로는 실패를 던진다면 설명과 구현이 다르다. 오류를 결과 타입에 포함하거나, 검증에 성공한 입력만 받는 경계를 정해야 한다. 범주론 용어를 도입하기 전에 함수가 무엇을 받아 무엇을 내놓는지부터 사실대로 적겠다.

합성의 결합법칙은 실행 순서를 마음대로 바꾸라는 뜻이 아니다

함수 합성의 결합법칙은 h ∘ (g ∘ f)(h ∘ g) ∘ f를 같게 묶을 수 있다는 뜻이다. 여기서 실행 순서는 여전히 f, g, h다. fg를 서로 바꿔도 된다는 교환법칙이 아니다. 파이프라인 그림을 읽을 때 가장 쉽게 놓치는 구분이다.

원고를 검증한 뒤 공개 형식으로 바꾸는 작업을 생각해 보자. 제목을 잘라 표시하는 변환을 먼저 수행하면 원본 제목 길이 검사와 결과가 달라질 수 있다. 날짜를 문자열로 바꾼 뒤 다시 해석하는 경로와 날짜 객체에서 직접 발행일을 계산하는 경로도 같은 결과인지 확인해야 한다.

아래 코드는 함수 합성의 묶음만 확인하는 설명용 예시다. 네트워크, 파일 수정이나 실제 블로그 배포는 수행하지 않는다.

const compose = (after, before) => value => after(before(value));
const trim = value => value.trim();
const upper = value => value.toUpperCase();
const wrap = value => `[${value}]`;
const sample = "  post  ";

const left = compose(wrap, compose(upper, trim))(sample);
const right = compose(compose(wrap, upper), trim)(sample);
console.assert(left === right && left === "[POST]");

한 예제가 통과한 것은 이 샘플의 계산을 확인한 것이다. 임의의 복잡한 시스템이 올바르다는 증명은 아니다. 수학적 전체 함수의 합성에서 성립하는 법칙과, 운영 코드에서 해당 가정이 지켜지는지를 검사하는 일은 나눠야 한다. 시간, 난수, 외부 상태에 의존하는 함수를 섞으면 같은 입력의 결과가 달라질 수 있다.

실무에서는 먼저 순수한 변환과 부작용을 분리하겠다. 제목 정규화나 표시 자료 생성은 입력만으로 계산하게 하고, 저장과 외부 전송은 별도 단계로 둔다. 그러면 변환의 오류와 저장 실패를 다른 검사로 확인할 수 있다. 이것은 모든 시스템을 순수 함수로 바꾸자는 주장이 아니라 검사 가능한 부분을 찾는 방법이다.

동형은 비슷해 보이는 두 시스템을 뜻하지 않는다

동형이라는 말을 ‘구조가 비슷하니 코드를 재사용할 수 있다’는 뜻으로 쓰면 조건이 너무 느슨해진다. 여기서 다루는 집합과 함수의 예에서는 두 방향의 변환을 합성했을 때 양쪽 모두 원래 값으로 돌아와야 한다. 한 방향의 변환이 있다는 사실만으로는 충분하지 않다.

예를 들어 제목과 본문만 가진 레코드를 같은 두 문자열의 쌍으로 바꾸는 변환을 생각할 수 있다. 허용하는 값의 범위를 정확히 정하고 추가 필드가 없으며 순서도 고정한다면, 다시 레코드로 돌리는 변환을 만들 수 있다. 반면 본문을 100자로 자른 카드로 바꾸면 많은 서로 다른 원문이 같은 카드가 된다. 카드에서 원문 전체를 복원할 수 없으므로 같은 주장을 할 수 없다.

이 차이는 백업과 검색에서 중요하다. 검색 인덱스와 요약은 원본에서 파생된 자료일 수 있지만 원본을 대신하는 백업이라고 볼 수 없다. 검색에 필요한 표현만 남겼다면 삭제한 정보가 무엇인지 설명해야 한다. ‘변환했다’와 ‘복원 가능하게 변환했다’를 구분하지 않으면 데이터 이전 계획이 잘못된다.

실제 변환을 검토할 때에는 양방향 왕복 사례를 준비한다. A를 B로 바꿨다가 A로 되돌렸을 때 필드가 보존되는지, B 쪽에서도 같은 조건이 성립하는지 본다. 숫자 정밀도, 누락값, 필드 순서와 문자 정규화처럼 값의 같음을 어떻게 정의하는지도 정한다. JSON 문자열이 문자 단위로 같은 것과 의미상 같은 객체인 것은 다른 검사다.

이런 검사가 몇 개 통과했다고 모든 입력에 대한 동형을 증명한 것은 아니다. 제한된 도메인에서 전수 검사가 가능한지, 일반 입력에는 어떤 논증과 속성 기반 검사가 필요한지 구분한다. 금융 시스템에서 쓰던 검증 코드를 다른 도메인에 옮길 때도 전제 조건을 다시 확인해야 한다. 이름이 비슷한 데이터라는 이유로 기존 보증이 따라오지는 않는다.

요네다 보조정리는 호환성 검사표를 대신하지 않는다

요네다 보조정리는 객체를 관계를 통해 이해한다는 직관으로 자주 소개된다. 정확한 정리는 범주, 집합값 함자와 자연변환 같은 조건을 다룬다. 선택한 관찰 몇 개가 같다고 두 소프트웨어 시스템이 완전히 같아진다는 말은 아니다. Milewski의 요네다 보조정리 설명

API가 같은 JSON을 반환하는 두 서비스도 인증, 실패 방식, 지연과 동시성에서 다를 수 있다. 클라이언트가 성공 응답만 관찰했다면 그 차이를 보지 못한다. ‘외부 인터페이스가 있으니 내부를 몰라도 된다’는 설계 원칙과 ‘관측 가능한 모든 관계에 관한 수학적 조건이 충족됐다’는 주장은 다르다.

내가 실무에서 가져올 질문은 더 작다. 이 모듈을 쓰는 호출자는 어떤 동작을 관찰하는가. 정상 결과 외에 어떤 오류가 계약에 포함되는가. 새 구현으로 바꿨을 때 보존해야 할 관찰은 무엇인가. 답을 정한 뒤 계약 테스트를 설계할 수 있다. 그 검사를 요네다 정리의 증명이라고 부르지는 않겠다.

교체 가능한 구현이라고 판단할 때에도 범위를 적는다. 예를 들어 문서 목록 조회에서 식별자와 정렬 순서를 보존하는지 확인한 것인지, 쓰기 충돌과 권한까지 검사한 것인지 구분한다. 한정된 호환성을 ‘완벽한 상호 운용성’으로 확대하지 않는 것이 중요하다.

작은 변환표로 시작하면 설계에서 얻을 것이 분명해진다

Fong과 Spivak의 『Seven Sketches in Compositionality』는 데이터베이스, 회로와 동역학 등 구체적 응용을 범주적 구조와 연결하는 입문서다. 이 글에서 책 전체를 검증하거나 모든 수학적 도구를 적용한 것은 아니다. 더 공부할 원전의 위치를 확인하고, 합성을 중심으로 문제를 나누는 관점을 가져왔다. 저자들의 공개 원고

문서 파이프라인 하나를 점검한다면 다음 표부터 채우겠다. 도구 이름을 늘어놓기보다 각 변환에서 잃거나 보장하는 것을 적는다.

변환보존할 것잃을 수 있는 것필요한 확인
원문에서 내부 원고출처, 원본 식별자외부 사이트의 화면 배치본문·출처 대응
원고에서 목록 카드식별자, 제목 연결본문 전체와 세부 근거원문 이동 가능 여부
날짜에서 표시 문자열합의한 발행일원래 시각·시간대 정보경계 시각 사례
원고에서 검색 자료검색에 필요한 내용표현·서식·일부 메타데이터갱신·삭제 반영과 원본 연결

이 표에서 정보 손실이 의도된 것인지 확인한다. 목록 카드가 본문을 버리는 것은 목적에 맞을 수 있다. 다만 목록 카드를 원본 백업으로 쓰려 한다면 설계가 잘못됐다. 같은 변환도 사용하는 목적에 따라 허용 조건이 달라진다.

첫 학습 목표는 모든 시스템에 범주론 용어를 붙이는 것이 아니다. 연결 가능한 함수, 되돌릴 수 있는 변환, 특정 관찰만 보존하는 대체를 구별할 수 있으면 좋겠다. 수학을 더 공부할수록 비유를 넓히는 것보다 적용 조건을 정확히 말하는 데 도움이 되어야 한다.

참고자료

범주론을 시스템 설계에 가져오기: 합성·정보 손실·호환성의 경계 · iamlazyck