일시적 버그 방지

이 페이지는 개발자가 일시적 버그를 방지하기 위한 구조적 패턴 및 팁을 다룹니다.

일반적인 원인

일시적 버그를 다룰 때 자주 나타나는 몇 가지 원인을 발견했습니다.

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

프론트엔드

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

여러 요청을 처리할 때, 응답의 순서가 요청되는 순서와 일치한다고 가정하는 것은 쉽습니다.

하지만 실제로는 그렇지 않을 수 있으며, 이는 순서가 변경되면 발생하는 버그를 유발할 수 있습니다.

예시:

  • diffs_metadata.json (가벼움)
  • diffs_batch.json (무거움)

만약 여러 요청에서 데이터가 필요한 경우, 해당 데이터가 작업하기 전에 두 요청이 완료된 것을 확인하세요.

매뉴얼 테스트 시 느린 연결 시뮬레이션

브라우저의 개발자 도구에 네트워크 조건 템플릿을 추가하여 느린 연결과 빠른 연결 사이를 전환할 수 있도록 합니다.

예시:

  • 느린 연결:
    • 다운로드: 50kb/s
    • 업로드: 20kb/s
    • 지연 시간: 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 계약을 충족하는지 여부를 감지하는 것입니다.

관련 독서

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

백엔드

락을 사용하는 Sidekiq 작업

Sidekiq을 통해 비동기 작업을 처리할 때, 동일한 매개변수를 가진 2개의 작업이 동시에 수행될 수 있습니다. 올바르게 처리되지 않으면 구식 또는 부정확한 상태로 이어질 수 있습니다.

예를 들어, 개체의 상태를 업데이트하는 워커가 있을 때, 워커가 개체의 상태를 업데이트하기 전에 적절한 상태를 확인해야 할 것입니다.

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

  1. (워커 A) #check_state 호출
  2. (워커 B) #check_state 호출
  3. (워커 B) #update_state 호출
  4. (워커 A) #update_state 호출

이 예시에서 워커 B가 업데이트된 상태를 설정해야하지만, 워커 A#update_state를 너무 늦게 호출하게 됩니다.

이를 방지하기 위해 데이터베이스 락이나 Gitlab::ExclusiveLease를 활용할 수 있습니다. 이렇게 하면 작업이 한 번에 하나씩 수행됩니다. 이는 그들을 멱등성으로 표시할 수 있게 합니다.

재시도 메커니즘 처리

객체/레코드가 다시 확인될 수 있는 실패 상태에 있을 수 있는 경우가 있습니다.

객체가 다시 확인될 수 있는 상태에 있는 경우, 사용자가 무엇을 해야 하는지 알 수 있도록 적절한 메시지가 표시되고, 재시도 기능이 트리거될 때 상태가 올바르게 재설정되도록 해야 합니다.

오류 로깅

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

코딩 중에 때로는 예외가 발생할 것으로 예상하고 예외를 잡습니다.

오류를 잡을 때마다 오류가 로깅되면, 사용자가 볼 수 있는 일시적 버그를 유발하는 원인이 될 수 있습니다. 버그 보고를 조사하는 동안, 엔지니어는 그것이 발생한 로그를 살펴볼 수도 있습니다. 로그를 확인할 때 오류를 확인할 때 오류가 기록된 것을 보게 되면, 이는 다르게 처리될 수 있는 문제의 신호가 될 수 있습니다.