프로그래밍에서 멱등성은 같은 작업을 한 번 하든 여러 번 하든 결과가 달라지지 않는 성질이다. 통신 오류로 요청을 재전송할 수 있는 네트워크 서비스뿐 아니라 임베디드 기기를 설계할 때도 이를 고려하면 중복 실행으로 생기는 문제를 줄일 수 있다.
프로그래밍에 익숙해지면 일부 작업을 자동으로 처리하듯 반복하게 된다. 문법 오류는 컴퓨터가 잡아내지만, 정적 분석 도구인 lint와 FindBugs도 높은 수준의 소프트웨어 설계 오류까지 찾아주지는 않는다. Code Complete, The Pragmatic Programmer, Effective C++, Effective Java 같은 책과 동료의 피드백을 통해 좋은 프로그래밍 관행을 익히고 되짚어야 한다는 것이 제이슨 M. 삭스(Jason M. Sachs)의 설명이다.
멱등성이란 작업을 한 번 수행하든 여러 번 수행하든 최종 결과가 같다는 뜻이다. 예를 들어 은행 계좌에 잔액이 1180달러 남아 있을 때 60달러를 인출하는 작업은 반복해도 잔액이 1120달러가 된다. 반면 주식 100주 매도나 학생 한 명을 돕는 작업을 반복하면 결과가 달라진다. 자동차를 이미 빨갛게 칠한 뒤 다시 칠하는 것처럼 결과는 같아도 비용이 반복해서 들 수 있다.
이 특성은 네트워크 소켓, 직렬 포트, SPI나 I2C 칩처럼 데이터가 제대로 도착한다고 보장할 수 없는 통신에서 중요하다. 송신 측은 응답이 없으면 요청을 재전송할 수 있기 때문이다. 전자상거래 사이트에서 제출 버튼을 두 번 눌러 같은 상품을 두 번 주문하는 사례는 중복 요청을 멱등하지 않게 처리할 때 생긴다. 버튼을 비활성화하는 방식은 고객이 연결 문제로 페이지를 새로고침한 뒤 주문 여부를 모르는 상황을 해결하지 못할 수 있다.
대안은 거래마다 고유 ID를 부여하고 서버가 같은 거래를 한 번만 처리하도록 하는 것이다. 같은 ID를 가진 요청이 반복되면 첫 요청만 실행하고 이후 요청은 무시하거나 이미 접수됐다고 알릴 수 있다. 그러면 고객이나 브라우저가 실수하지 않는다는 전제에 의존하지 않아도 된다. 거래 ID를 사용하는 방법은 이런 설계의 한 예다.
멱등성은 전자레인지나 차고 문 개폐기 같은 간단한 임베디드 시스템에도 적용할 수 있다. 버튼을 여러 번 눌렀을 때마다 ‘현재 상태를 반대로 바꾸라’고 전달하면, 신호가 반복되거나 사용자가 문 움직임을 보지 못해 다시 누를 때 문이 반대 방향으로 움직일 수 있다. 목표 상태를 전달하는 방식이라면 스위치가 위에 있을 때는 ‘문 열기’, 아래에 있을 때는 ‘문 닫기’를 보낼 수 있다. 다만 이 방식은 장치가 문 상태를 알아야 하고 송신기와 소프트웨어를 바꿔야 하며, 송신기가 여러 개일 때 상충하는 입력도 처리해야 해 실제 적용이 쉽지 않을 수 있다.
입력 장치를 설계할 때는 버튼뿐 아니라 손잡이나 토글 스위치도 고려할 만하다. 현재 상태를 뒤집는 대신 원하는 상태를 지정하면 같은 입력이 반복돼도 결과가 달라지지 않는다. 또 다른 방법은 작업 전의 상태와 원하는 작업 후 상태를 함께 보내는 것이다. 이 방식은 세마포어 구현에 쓰이는 compare-and-swap 연산에서 볼 수 있다.
멱등하지 않은 작업에는 변수를 증가시키거나 상태를 토글하거나 다음 상태로 진행하는 동작이 있다. 반대로 특정 변수를 정해진 값으로 설정하거나, 현재 상태가 X일 때 Y로 바꾸거나, 아직 실행되지 않은 고유 ID의 거래만 처리하는 동작은 멱등하게 설계할 수 있다.
삭스는 멱등성을 시스템 신뢰성을 높이는 반복 쓰기에도 활용할 수 있다고 설명한다. 그가 소개한 회로에는 마이크로컨트롤러와 SPI DAC가 있었지만, DAC에 직렬 출력 핀이 없어 데이터를 읽어올 수 없었다. DAC의 SPI 통신에는 체크섬도 없었고, 칩 사이 거리는 약 4인치였으며 주변에는 스위칭 전력 전자 장치가 있었다. 그는 DAC에 값을 쓸 때마다 상위 3비트가 잘못 전달될 가능성을 10⁻⁹으로 가정했다.
이 가정에서 DAC를 한 시간마다 쓰면 특정 해에 오류를 겪을 확률은 약 114,080분의 1이지만, 오류가 나면 한 시간 동안 유지된다. 초당 한 번 쓰면 연간 오류 확률은 약 31.7분의 1이고 오류는 1초간 지속된다. 밀리초마다 쓰면 오류 사이 평균 시간이 11.57일로 줄지만, 각각의 오류는 1밀리초만 지속된다. 해당 시스템은 전원을 켤 때만 DAC 값을 설정하면 됐지만, 오류가 발생하면 그 영향이 며칠간 이어질 수 있어 몇 밀리초마다 값을 다시 썼다. 읽기 기능이 있는 DAC를 쓰고 싶었지만 회로 설계 때 이를 놓친 대신 반복 쓰기로 위험을 줄였다는 설명이다.
댓글 (0)
로그인하면 이 기사에 내 생각을 남길 수 있어요