Haeminway haeminway
English
활용 가이드로
6 분 분량

Google Forms 데이터는 왜 며칠 만에 지저분해지는가

Google Forms 응답 데이터가 며칠 만에 지저분해지는 이유와 수집 직후 정리해야 하는 기준을 설명합니다.

결론 먼저: Google Forms 데이터는 왜 며칠 만에 지저분해지는가라는 제목은 세게 잡았지만, 실제 핵심은 클릭 장사가 아니라 운영 설계입니다. 이 문제는 “툴을 하나 더 쓰면 해결”이 아니라 원본, 로그, 권한, 재시도, 동시성을 어떻게 잡느냐의 문제입니다.

핵심

좋은 자동화는 버튼이 아니라 증거를 남깁니다. 누가, 언제, 어떤 입력으로, 어떤 결과를 만들었고, 실패하면 어디까지 반영됐는지 설명할 수 있어야 합니다.

1. 왜 이런 일이 생기나

Google Forms 데이터는 왜 며칠 만에 지저분해지는가 운영 구조 도식

데모에서는 한 사람이 한 번 누릅니다. 실제 업무에서는 같은 폼이 두 번 제출되고, 네트워크가 끊기고, 담당자가 시트를 정렬하고, 브라우저가 저장소를 비우고, 외부 API가 느려지고, 관리자가 권한을 바꿉니다. 자동화가 무너지는 지점은 대부분 여기입니다.

특히 Google Apps Script와 시트 기반 자동화는 시작이 쉽습니다. 그래서 더 위험합니다. onFormSubmit 하나, 시간 기반 트리거 하나, 확인메일 하나를 붙이면 그럴듯한 업무 시스템처럼 보입니다. 하지만 아래 다섯 가지가 없으면 시스템이 아니라 “운 좋게 도는 스크립트”입니다.

필요한 것없을 때 벌어지는 일
고유 ID같은 요청이 두 번 반영됩니다
원본/정제/로그 분리사람이 고친 값과 자동화가 쓴 값이 섞입니다
실패 로그고객이 알려줄 때까지 멈춘 줄 모릅니다
잠금/큐동시 제출 때 마지막 저장이 앞 저장을 덮습니다
롤백 기준배포 후 깨져도 어디로 돌아갈지 모릅니다

관련 기본기는 앱스크립트 자동화 가이드, 6분 실행 한도, LockService 동시성, 재시도와 멱등키를 같이 봐야 합니다.

2. 먼저 확인할 것

현재 사용하는 시트나 스크립트에는 아래 항목이 있는지 확인이 필요합니다. 기능 추가보다 이 점검이 먼저입니다.

  1. 입력마다 UUID나 폼 응답 ID가 있습니까?
  2. 원본 응답 시트를 사람이 직접 고치지 않습니까?
  3. 자동화 실행 결과가 runs 같은 로그 시트에 남는가.
  4. 실패했을 때 담당자에게 알림이 가는가.
  5. 같은 요청을 두 번 실행해도 결과가 한 번만 반영되는가.
  6. appsscript.json 권한 범위가 설명 가능한가.
  7. 이전 배포 버전이나 이전 시트 백업으로 돌아갈 수 있는가.

3. 추천 시트 구조

업무가 작아도 시트는 최소 네 장으로 나누는 게 좋습니다.

시트역할사람이 직접 수정?
raw폼·외부 API 원본금지
clean정규화된 업무 데이터제한적 허용
ledger승인·예약·발송·재고 같은 사건 기록금지
runs스크립트 실행 로그금지

raw는 증거입니다. clean은 사람이 보는 표입니다. ledger는 돈, 예약, 재고, 승인처럼 나중에 설명해야 하는 사건입니다. runs는 자동화의 블랙박스입니다. 이 네 장을 섞으면 나중에 값 하나가 틀렸을 때 원인을 찾을 수 없습니다.

4. 구현 뼈대

아래 구조가 핵심입니다. 실제 업무 로직보다 먼저 ID, 잠금, 실패 로그, 중복 방지가 들어갑니다.

function runJob(event) {
  const id = event.id || Utilities.getUuid();
  const lock = LockService.getScriptLock();
  if (!lock.tryLock(10000)) throw new Error('busy: retry later');
  const started = Date.now();
  try {
    if (alreadyProcessed_(id)) return { id, skipped: true };
    const normalized = normalizeInput_(event);
    validate_(normalized);
    const result = doWork_(normalized);
    markProcessed_(id, result);
    logRun_('job', Date.now() - started, 'ok', id, '');
    return result;
  } catch (err) {
    logRun_('job', Date.now() - started, 'error', id, String(err.message || err));
    throw err;
  } finally {
    SpreadsheetApp.flush();
    lock.releaseLock();
  }
}

이 뼈대에서 중요한 건 doWork_()가 아닙니다. 진짜 중요한 건 그 앞뒤입니다. 이미 처리한 ID인지 확인하고, 동시에 두 실행이 같은 값을 만지지 못하게 잠그고, 실패해도 로그를 남기고, 마지막에 flush()로 시트 쓰기를 확정합니다. 이게 없으면 코드는 짧아 보이지만 운영은 길어집니다.

5. 판단 기준

아래 기준으로 “그냥 시트+Apps Script로 충분한지”와 “전용 SaaS나 서버가 필요한지”를 가릅니다.

상황시트+Apps Script전용 SaaS/서버
하루 수십~수백 건 입력적합과함
동시 제출이 가끔 있음LockService로 가능초당 다수면 필요
결제·법적 증빙이 핵심보조 기록까지만전문 도구 권장
이미지·파일 대량 저장Drive/IndexedDB 조합전용 저장소 권장
외부 API가 여러 개가능하나 로그 필수장애 격리 필요

이 선을 넘으면 GAS를 떠나야 할 신호를 봐야 합니다. 작은 도구로 시작하는 건 좋지만, 작은 도구로 영원히 버티겠다는 뜻은 아닙니다.

6. 하지 말아야 할 것

  • 행 번호를 ID로 쓰면 정렬이나 삭제 한 번에 기준이 깨질 수 있습니다.
  • 원본 응답 시트 위에 수식과 수동 수정이 섞이면 추적이 어려워집니다.
  • catch (e) {}로 에러를 삼키면 실패 원인을 나중에 찾기 어렵습니다.
  • 외부 API 키를 코드에 직접 쓰면 권한 이전과 유출 대응이 어려워집니다. AI 비용과 키 관리를 참고할 수 있습니다.
  • 자동메일, 예약 확정, 재고 차감처럼 되돌리기 어려운 작업은 검수 단계를 두는 편이 안전합니다.
  • 무료 한도 안이라도 모니터링이 없으면 장애를 늦게 발견하게 됩니다.

마지막 점검 기준

이 글의 기준은 기능 목록이 아니라 운영 가능성입니다. 아래 네 가지가 갖춰져 있으면 작은 업무 자동화로는 꽤 안전한 편이고, 빠져 있으면 데모 단계에 가깝습니다.

  • 원본 데이터와 사람이 보는 화면이 분리되어 있는가
  • 실행 로그에 성공, 실패, 처리 건수, 오류 메시지가 남는가
  • 같은 입력이 다시 들어와도 결과가 중복되지 않는가
  • 권한 변경, 쿼터 초과, 외부 API 실패를 나중에 확인할 수 있는가

고객 응대, 예약 확정, 재고 차감, 결제처럼 되돌리기 어려운 업무라면 기준이 더 높아집니다. 그때는 Apps Script만으로 충분한지, 전용 SaaS나 별도 서버 구성이 더 안전한지까지 같이 봐야 합니다.

자주 묻는 질문

이 글은 어떤 사람에게 필요한가요?
구글 시트, 폼, 캘린더, Apps Script로 업무 자동화를 만들었거나 만들려는 사람에게 필요합니다. 특히 이미 데모는 되는데 운영 안정성이 걱정되는 경우에 맞습니다.
바로 구현할 때 가장 먼저 해야 할 일은 무엇인가요?
원본 시트와 업무 시트를 분리하고, runs 로그 시트를 만들어 마지막 성공·실패·실행시간을 남기는 일부터 해야 합니다.
Apps Script로 충분하지 않은 경우는 언제인가요?
동시 요청이 많거나 결제·법적 증빙·대용량 파일·실시간 양방향 동기화가 핵심이면 전용 SaaS, 외부 DB, 서버 큐를 검토해야 합니다.