[나의 앱개발기] 개발자 아닌 직장인이 구글폼 실시간 접수 현황판 만든 과정 (앱스스크립트 + AI)
행사 하나 열면 제일 많이 하는 일이 뭔지 아세요. 구글폼 응답 시트 열어서 스크롤 맨 아래로 내리고, 행 번호 확인하고, 헤더 한 줄 빼고, 다시 창 닫기. 이걸 하루에 열 번씩 합니다. 그러다 누가 물어보죠. "지금 몇 명이야?" 그럼 또 시트를 엽니다.
간담회랑 소모임 신청을 동시에 받던 날, 시트 두 개를 번갈아 열다가 결국 만들기로 했습니다. "주소만 붙여넣으면 몇 명인지 계속 보여주는 화면" 하나면 끝나는 일이었거든요. 개발자는 아닙니다. 그런데 요즘은 그게 큰 문제가 아니더라고요.
* 왜 앱스스크립트였나.
처음엔 스프레드시트 안에서 끝낼까 했습니다. 셀 하나에 COUNTA 걸어두면 되니까요. 그런데 그건 결국 시트를 열어야 보입니다. 문제가 그대로 남는 거죠. 폰으로 툭 열어서 보고, 사무실 모니터에 띄워두고, 다른 사람한테 주소만 던져줄 수 있어야 했습니다.
| 방법 | 만드는 난이도 | 폰에서 보기 | 여러 건 동시 |
|---|---|---|---|
| 시트에 COUNTA 함수 | 매우 쉬움 | 불편 | 불가 |
| 구글 데이터스튜디오 | 보통 | 가능 | 가능 |
| 앱스스크립트 웹앱 | 보통 | 가능 | 가능 |
| 외부 서비스 결제 | 쉬움 | 가능 | 가능 |
데이터스튜디오도 괜찮은 선택입니다. 다만 원하는 대로 화면을 주무르기가 답답하고, 중복 신청을 어떻게 셀지 같은 우리 조직만의 규칙을 넣기가 번거롭죠. 외부 서비스는 월 구독료가 붙습니다. 앱스스크립트는 구글 계정만 있으면 0원이고, 이미 구글폼·시트를 쓰고 있으니 권한 문제도 깔끔하고요.
* 1차 버전 : 숫자 하나만 크게.
첫 목표는 딱 하나였습니다. 주소를 붙여넣으면 숫자가 뜬다. 그 이상은 안 만들기로 했어요. 욕심내면 못 끝냅니다.
1. 파일 구성.
앱스스크립트 웹앱은 보통 파일 두 개면 됩니다. 서버 역할을 하는 Code.gs, 화면을 그리는 Index.html. 서버가 시트에서 데이터를 세어 숫자를 돌려주고, 화면은 그 숫자를 크게 띄우고 몇 초마다 다시 물어봅니다. 구조는 이게 전부예요.
2. 신청 인원을 세는 규칙.
여기가 의외로 함정입니다. 그냥 마지막 행 번호를 쓰면 안 되더라고요. 시트를 만지다 보면 빈 행이 끼고, 같은 사람이 두 번 신청하기도 하니까요. 그래서 규칙을 이렇게 정했습니다.
신청 인원 = 내용이 있는 행 수 − 중복 건수
중복 기준은 사번이나 이메일처럼 사람마다 하나뿐인 열로 잡습니다. 이름은 동명이인이 있으니 위험하죠. 실제로 저희 시트에서도 2건이 중복으로 걸러졌습니다. 그냥 셌으면 인원 보고가 어긋날 뻔했던 거죠.
3. 주소에서 시트 찾아내기.
붙여넣는 주소에는 정보가 두 개 들어 있습니다. 파일 아이디, 그리고 gid라는 시트 번호. 앞부분으로 파일을 열고, 뒤 번호로 어느 탭인지 찾습니다. 응답 시트가 여러 개인 파일도 있으니까요. 이걸 자동으로 읽어주니 사용자는 주소만 복사하면 끝입니다.
* 2차 : 행사가 하나가 아니었다.
하루 써보고 바로 한계가 왔습니다. 간담회 신청도 받고, 야구 응원 소모임도 받고 있었거든요. 화면 하나에 하나만 보이면 결국 창을 두 개 띄워야 합니다. 처음 문제로 되돌아온 셈이죠.
그래서 구조를 바꿨습니다. 등록한 현황을 카드로 쭉 늘어놓고, 카드를 누르면 그 건의 상세가 열리는 방식으로요. 홈에서는 인원과 오늘 신청 수만, 상세에서는 오늘·최근 1시간·중복 제외·최근 접수 명단까지.
1. 여기서 배운 것 하나.
카드가 5개면 서버에 5번 물어봐야 할까요. 처음엔 그렇게 짰습니다. 그런데 앱스스크립트는 호출 하나하나가 느립니다. 심부름을 다섯 번 보내는 셈이니까요. 그래서 목록을 통째로 넘기고 한 번에 다 세어서 돌려받게 바꿨습니다.
| 방식 | 카드 5개일 때 호출 | 체감 속도 |
|---|---|---|
| 카드마다 따로 요청 | 5회 | 하나씩 늦게 뜸 |
| 한 번에 묶어서 요청 | 1회 | 동시에 갱신 |
대신 한 건이 실패하면 전부 멈추는 위험이 생기죠. 그래서 각각 따로 감싸서, 권한이 없는 시트 하나가 있어도 그 카드에만 사유가 뜨고 나머지는 정상으로 돕니다. 이런 건 만들어보기 전엔 생각도 못 했던 부분이에요.
* 3차 : 폰에서 보이게 만들기.
현장에서 쓰는 도구는 결국 폰으로 봅니다. 행사장 입구에서 노트북 열고 있을 수는 없잖아요? 그런데 데스크톱 기준으로 만든 화면을 폰으로 열면 티가 확 납니다.
입력창 글자는 16px 이상
누르는 버튼은 44px 이상
노치·홈바 영역까지 계산!
입력창 글자를 16px 미만으로 두면 아이폰에서 탭할 때마다 화면이 확 커집니다. 버튼은 손가락 기준으로 44px 아래로 내려가면 자꾸 헛누르게 되고요. 요즘 폰은 위아래에 노치랑 홈바가 있어서, 그 영역을 피하는 여백도 따로 넣어야 합니다. "모바일 대응은 화면을 줄이는 게 아니라 손가락에 맞추는 일"이라는 걸 이때 알았습니다.
배터리 얘기도 하나. 몇 초마다 서버에 물어보는 화면이라, 폰을 주머니에 넣어둔 동안에도 계속 돌면 낭비죠. 그래서 화면이 뒤로 넘어가면 요청을 멈추게 했습니다. 구글 앱스스크립트는 하루 실행 할당량도 있어서, 이건 안정성 문제이기도 합니다.
* 마지막은 결국 써본 사람이 안다.
다 만들었다고 생각한 다음에 나온 요구가 제일 실용적이었습니다. "카드 지우려고 상세까지 들어가는 게 번거롭다. 카드 오른쪽 위에 X 있으면 좋겠다."
맞는 말이죠. 지난 행사 현황판은 끝나면 목록에서 치워야 하는데, 그때마다 두 번 이동해야 했으니까요. 다만 X를 누르자마자 삭제되면 실수로 날아갑니다. 그래서 X를 누르면 그 카드 안에서 바로 확인 문구가 뜨고, 한 번 더 눌러야 사라지게 했습니다. 카드 클릭과 X 클릭이 서로 간섭하지 않게 하는 처리도 같이 넣었고요.
* AI랑 같이 만들 때 효과 있었던 방식.
1. 한 번에 하나씩 요청하기.
처음부터 "멀티 카드에 모바일 대응에 삭제 기능까지"라고 던졌으면 아마 못 끝냈을 겁니다. 숫자 하나 뜨는 것부터 만들고, 써보고, 불편한 걸 하나씩 얹었어요. 이게 결과적으로 훨씬 빨랐습니다.
2. 부분 수정 말고 전체 파일로 받기.
"이 줄을 이렇게 바꾸세요" 식으로 받으면 코딩 모르는 사람은 붙여넣다가 꼬입니다. 저는 항상 파일 전체를 다시 달라고 합니다. 통째로 갈아끼우면 실수할 일이 없거든요.
3. 화면을 캡처해서 보여주기.
말로 "카드 오른쪽 위"라고 설명하는 것보다, 지금 화면을 찍어서 던지고 "여기에 X"라고 하는 게 훨씬 정확합니다. 실제로 이 프로그램에서 마지막 기능이 그렇게 붙었어요.
* 마무리 정리.
결국 만든 건 대단한 프로그램이 아닙니다. 주소를 넣으면 숫자를 세어주는 화면 하나죠. 그런데 하루에 열 번 하던 일이 사라졌고, 누가 물어보면 주소만 보내면 됩니다.
개발을 배워야 만들 수 있는 시대는 지난 것 같습니다. 대신 "내 업무에서 뭐가 반복되고 있는지 정확히 아는 사람"이 유리해졌죠. 무엇을 만들지 정하는 건 여전히 사람 몫이니까요. 저는 그게 더 재밌더라고요.
업무 환경과 권한 설정에 따라 동작이 다를 수 있습니다.