[]
동시 작업 편집에서 충돌(conflict)이란 여러 사용자가 문서의 동일하거나 관련된 부분을 동시에 편집하여, 각자의 편집 작업이 서로 영향을 주거나 간섭함으로써 문서의 일관성이나 사용자의 의도를 훼손할 수 있는 상황을 의미합니다.
동시 편집이 발생하는 경우, 시스템은 다음을 보장해야 합니다.
모든 사본 간 데이터 일관성 유지: 최종적으로 각 사본의 데이터가 동일하게 유지되어야 함
사용자 의도의 최대한 보존: 최종 결과는 가능한 한 사용자의 기대에 부합해야 함. 다만 일부 충돌 상황에서는 모든 사용자의 의도를 동시에 만족시키기 어려울 수 있음
다음 예제의 작업(Op)은 설명을 단순화한 것입니다. 실제 환경에서는 문서 타입, 작업 복잡도, 구현 방식에 따라 Op의 구조와 내용이 달라질 수 있습니다.
초기 텍스트가 "xyz"인 공유 문서를 두 클라이언트(Client A, Client B)가 동시에 편집한다고 가정합니다.
Client A: 위치 1(“x”와 “y” 사이)에 "a"를 삽입하여 결과가 "xayz"가 되기를 기대
Client B: 위치 2(“y”와 “z” 사이)에 "b"를 삽입하여 결과가 "xybz"가 되기를 기대
서버가 수신한 순서대로 작업(op)을 단순 적용·브로드캐스트만 한다면, 다음 그림과 같은 불일치 상황이 발생합니다.
네트워크 지연 등의 이유로 메시지 전송과 브로드캐스트는 즉시 전달되지 않습니다. 아래 그림은 이를 단순화하여 표현합니다.

설명
초기 상태: 모든 클라이언트와 서버의 텍스트는 "xyz"
로컬 작업 실행:
Client A가 { pos: 1, text: 'a' }를 실행하여 "xayz"가 됨
Client B가 { pos: 2, text: 'b' }를 실행하여 "xybz"가 됨
제출 및 서버 처리:
서버는 a를 먼저 적용 및 브로드캐스트 ("xyz" → "xayz"), 이후 b를 적용 ("xayz" → "xabyz")
클라이언트 수신 및 적용:
Client A는 b({ pos: 2, text: 'b' })를 수신하여 "xayz"의 위치 2(“a”와 “y” 사이)에 "b"를 삽입, 결과 "xabyz"
Client B는 a({ pos: 1, text: 'a' })를 수신하여 "xybz"의 위치 1(“x”와 “y” 사이)에 "a"를 삽입, 결과 "xaybz"
결과: Client A는 "xabyz", Client B는 "xaybz"를 가지게 되어 불일치 발생
Operational Transformation(OT)은 이미 실행된 작업의 영향을 반영하도록 작업을 조정하여, 모든 클라이언트와 서버에서 최종 상태가 일관되도록 충돌을 해결합니다. 서버와 클라이언트 모두 수신한 작업을 변환(Transform)하여 동시 작업을 수용합니다.
위 예제에 대해 다음과 같은 Transform 규칙을 정의할 수 있습니다.
// side는 서버에 나중에 도착한 op를 나타냅니다. side === 'left'이면 op1이 op2보다 나중에 서버에 도착했음을 의미합니다.
function transform(op1, op2, side: 'left' | 'right') {
if (op1.pos > op2.pos || (op1.pos === op2.pos && side === 'left')) {
return { pos: op1.pos + op2.text.length, text: op1.text };
}
return op1;
}다이어그램: OT Transform을 적용한 처리 과정

설명:
초기 상태: 모든 클라이언트와 서버의 텍스트는 "xyz"
로컬 작업 실행:
Client A가 { pos: 1, text: 'a' }를 실행하여 "xayz"가 됨
Client B가 { pos: 2, text: 'b' }를 실행하여 "xybz"가 됨
제출 및 서버 처리:
서버는 a를 수신·적용하여 "xayz"가 됨
서버는 b를 수신하고 b를 변환: b_transformed = Transform(b, a, 'left')
b.pos (2) > a.pos (1)이므로 "a"의 길이(1)만큼 pos를 증가시켜 { pos: 3, text: 'b' }가 됨
서버는 b_transformed를 적용하여 "xayz"의 위치 3(“y”와 “z” 사이)에 "b"를 삽입, 결과 "xaybz"
브로드캐스트 및 적용:
Client A는 b_transformed({ pos: 3, text: 'b' })를 수신하여 "xayz"의 위치 3에 "b"를 삽입, 결과 "xaybz"
Client B는 a를 수신하고 a를 변환: a_transformed = Transform(a, b, 'right')
a.pos (1) < b.pos (2)이므로 pos는 변경되지 않아 { pos: 1, text: 'a' }가 됨
Client B는 "xybz"의 위치 1에 "a"를 삽입하여 "xaybz"가 됨
결과: 모든 클라이언트와 서버가 "xaybz"를 가지며, 최종 상태는 일관됨
Operational Transformation의 핵심은 동시 작업의 영향을 고려하여 작업을 동적으로 조정하는 데 있습니다. 이 방식은 문서 잠금 없이도 사용자가 자유롭게 편집할 수 있게 하면서 일관성을 보장하므로, 실시간 동시 작업 편집 시나리오에 매우 적합합니다.