일시적 버그 방지

이 페이지에서는 개발자들이 일시적 버그를 방지하기 위해 따라야 할 구조적 패턴과 팁을 다룹니다.

일반적인 근본 원인

우리는 일시적 버그를 처리할 때 자주 나타나는 몇 가지 근본적인 원인을 발견했습니다.

  • 백엔드 또는 프론트엔드에서 더 나은 상태 관리가 필요합니다.
  • 프론트엔드 코드에 개선 사항이 필요합니다.
  • 테스트 커버리지 부족.
  • 경합 조건.

프론트엔드

응답 순서에 의존하지 마세요

여러 요청을 처리할 때 응답 순서가 요청된 순서와 일치한다고 가정하는 것은 쉽지만 항상 그렇지는 않습니다. 이는 순서가 바뀌면 발생하는 버그를 일으킬 수 있습니다.

예시:

  • diffs_metadata.json (가벼움)
  • diffs_batch.json (무겁게)

만약 귀하의 기능이 양쪽 데이터에서 정보를 필요로 한다면, 해당 데이터가 작업되기 전에 두 데이터가 로딩이 완료되었는지 확인하세요.

매뉴얼 테스트 시 느린 연결 모의

브라우저의 개발자 도구에 네트워크 상태 템플릿을 추가하여 느린 연결과 빠른 연결 간에 전환할 수 있게 합니다.

예시:

  • 거북이:
    • 다운로드: 50kb/s
    • 업로드: 20kb/s
    • latency: 10000ms

축소된 요소

이벤트 리스너를 설정할 때 이벤트 위임을 사용할 수 없는 경우, 확장된 콘텐츠에 대해 모든 관련된 이벤트 리스너가 설정되었는지 확인하세요. 특히, 그 확장된 콘텐츠가 다음과 같은 경우에 잘 작동하는지 확인하세요.

  • 보이지 않는 (display: none;). 일부 JavaScript는 요소가 작동하려면 보이는 상태여야 하는데, 이는 메트릭을 수행할 때와 같이 일부 상황에서 필요합니다.
  • 동적 콘텐츠 (AJAX/DOM 조작).

미충족 조건에 의한 일시적 버그 감지를 위한 어서션 사용

일시적 버그는 응용 프로그램의 상태가 하나 이상의 조건을 충족한다는 가정 하에 실행되는 코드의 맥락에서 발생합니다. 우리는 서버 측 API 응답이 항상 특정 속성 그룹을 포함한다고 가정하거나 응용 프로그램이 성공적으로 새 상태로 전환된 경우에만 실행되는 작업 등을 가정하는 기능을 작성할 수 있습니다.

일시적인 버그는 미충족 조건에 대해 경고하는 메커니즘이 없기 때문에 디버깅하기 어렵습니다. 이러한 조건은 일반적으로 코드에서 명시적으로 표현되지 않습니다. 이러한 상황에 유용한 디버깅 기술 중 하나는 가정을 명시적으로 만들기 위해 어서션을 배치하는 것입니다. 어서션을 사용하면 미충족 조건이 버그를 일으킨 원인을 감지하는 데 도움이 될 수 있습니다.

상태 변이의 사전 조건 주장

미충족 조건에 대한 일시적 버그로 이어지는 일반적인 시나리오는 사용자 작업이 완료되었을 때에만 상태를 변이시키는 폴링 서비스가 있는 경우입니다. 이 때, 가정을 명시적으로 만들기 위해 어서션을 사용할 수 있습니다:

//이 작업은 폴링 서비스에 의해 호출됩니다. 작업이 디스패치되는 시점에 모든 사전 조건이 충족되었다고 가정합니다.
export const updateMergeableStatus = ({ commit }, payload) => {
  commit(types.SET_MERGEABLE_STATUS, payload);
};

// 어서션을 추가함으로써 모든 사전 조건을 명확하게 만들 수 있습니다.
export const updateMergeableStatus = ({ state, commit }, payload) => {
  console.assert(
    state.isResolvingDiscussion === true,
    'Resolve discussion request must be completed before updating mergeable status'
  );
  commit(types.SET_MERGEABLE_STATUS, payload);
};

API 계약 주장

어서션을 사용하는 또 다른 유용한 방법은 서버 측 엔드포인트에서 반환된 응답 페이로드가 API 계약을 충족하는지 여부를 감지하는 것입니다.

관련 독해 자료

디버깅!는 결정론적이지 않은 버그를 진단하고 수정하는 기술 및 더 쉽게 디버그할 수 있는 소프트웨어를 작성하는 기술을 탐구합니다.

백엔드

락과 함께 하는 Sidekiq 작업

Sidekiq을 통해 비동기 작업을 처리할 때, 동일한 인수를 가진 2개의 작업이 동시에 작동하게 될 수 있습니다. 이를 올바르게 처리하지 않으면 오래된 또는 부정확한 상태가 될 수 있습니다.

예를 들어, 객체의 상태를 업데이트하는 작업자를 고려해보십시오. 작업자가 객체의 상태를 업데이트하기 전에 (예를 들어 #check_state) 적절한 상태를 확인해야 하는 경우가 있습니다.

동시에 2개의 작업이 처리되고 있을 때, 작업의 순서는 다음과 같을 수 있습니다:

  1. (작업자 A) #check_state 호출
  2. (작업자 B) #check_state 호출
  3. (작업자 B) #update_state 호출
  4. (작업자 A) #update_state 호출

이 예에서, ‘작업자 B’가 업데이트된 상태를 설정해야 합니다. 그러나 ‘작업자 A’가 #update_state를 다소 늦게 호출합니다.

이러한 상황은 데이터베이스 락 또는 Gitlab::ExclusiveLease를 활용하여 피할 수 있습니다. 이렇게 하면 작업이 한 번에 하나씩 처리될 수 있습니다. 이는 또한 이러한 작업들이 멱등성으로 표시될 수 있게 합니다.

재시도 메커니즘 처리

객체/레코드가 실패 상태에 있을 수 있는 경우가 있습니다. 이러한 상태를 재확인할 수 있는 경우, 사용자가 무엇을 해야 하는지 알 수 있도록 적절한 메시징이 표시되도록 하십시오. 또한 재시도 기능이 트리거될 때 상태를 올바르게 재설정할 수 있도록 확인하십시오.

오류 로깅

오류 로깅은 일시적 버그를 직접적으로 방지하지는 않지만 디버깅에 도움이 될 수 있습니다.

코딩할 때, 때로는 예외가 발생할 것으로 예상하고 그 예외를 처리할 것을 기대합니다.

오류가 발생했을 때 로깅하는 것은 사용자가 볼 수 있는 일시적 버그를 일으키는 경우에 도움이 됩니다. 버그 보고서를 조사하는 동안 엔지니어가 발생한 시간대의 로그를 살펴보는 경우가 있습니다. 로그를 확인하면 무엇이 잘못되었는지에 대한 신호를 얻을 수 있으며, 이를 다르게 처리할 수 있습니다.