기본 커스텀 함수 작성과 구글 시트 연동 방법
커스텀 함수를 만들기 위한 첫 단계는 Apps Script 편집기에 접근하는 것입니다. 구글 시트에서 확장 프로그램 메뉴를 클릭하고 Apps Script를 선택하면 새로운 탭에서 코드 편집 환경이 열립니다. 기본적으로 빈 프로젝트가 생성되며, myFunction이라는 샘플 함수가 제공됩니다. 이 함수를 삭제하고 새로운 커스텀 함수를 작성합니다. 함수 선언은 자바스크립트 문법을 따르며, function 키워드 뒤에 함수명과 매개변수를 정의합니다. 가장 간단한 예제로 두 숫자를 곱하는 함수를 만들어보겠습니다. function MULTIPLY_CUSTOM(num1, num2)와 같이 선언하고, return num1 * num2로 결과를 반환합니다. 함수명은 대문자로 작성하는 것이 관례이며, 구글 시트의 기본 함수와 구분하기 위해 의미 있는 이름을 사용해야 합니다. 코드 작성이 완료되면 저장 버튼을 클릭하고 프로젝트명을 지정합니다. 구글 시트로 돌아가서 셀에 등호를 입력한 후 함수명을 타이핑하면 자동완성 목록에 나타납니다. 매개변수로 셀 참조나 직접 값을 전달할 수 있으며, 일반 함수와 동일하게 작동합니다. 문자열 처리 함수도 유용합니다. 예를 들어 텍스트에서 특정 패턴을 추출하거나, 여러 문자열을 특정 규칙에 따라 결합하는 함수를 만들 수 있습니다. 정규표현식을 활용하면 복잡한 텍스트 파싱도 가능합니다. match 메서드나 replace 메서드를 사용하여 원하는 패턴을 찾거나 변환합니다. 날짜 계산 함수는 업무에서 자주 필요합니다. 영업일 기준으로 며칠 후의 날짜를 계산하거나, 두 날짜 사이의 근무일수를 구하는 함수를 작성할 수 있습니다. Date 객체를 활용하여 날짜 연산을 수행하고, 공휴일 목록을 배열로 관리하여 제외 처리합니다. 조건부 로직을 포함한 함수도 강력합니다. if-else 문이나 switch 문을 사용하여 입력값에 따라 다른 결과를 반환하도록 구현합니다. 예를 들어 점수를 입력받아 등급을 반환하거나, 매출액에 따라 수수료율을 계산하는 함수를 만들 수 있습니다. 매개변수의 기본값을 설정하면 사용자 편의성이 향상됩니다. ES6 문법을 사용하여 function CALCULATE(value, rate = 0.1)과 같이 작성하면, rate 값을 생략했을 때 자동으로 0.1이 적용됩니다. 여러 개의 매개변수를 받아야 할 때는 나머지 매개변수 문법을 활용합니다. function SUM_CUSTOM(...numbers)로 선언하면 가변 개수의 인자를 배열로 받을 수 있습니다. 에러 처리도 중요한 요소입니다. try-catch 블록으로 예외 상황을 처리하고, 적절한 에러 메시지를 반환하여 사용자가 문제를 파악할 수 있도록 합니다. 함수 내에서 다른 함수를 호출하는 것도 가능합니다. 복잡한 로직을 여러 개의 작은 함수로 분리하여 재사용성과 유지보수성을 높입니다. 주석을 충분히 작성하여 각 함수의 목적과 매개변수, 반환값을 명확히 기록해야 합니다. JSDoc 형식으로 주석을 작성하면 자동완성 시 설명이 표시되어 편리합니다.
API 연동과 외부 데이터 활용 고급 기법
커스텀 함수의 진정한 강력함은 외부 API와 연동하여 실시간 데이터를 가져올 수 있다는 점에 있습니다. UrlFetchApp 서비스를 사용하면 HTTP 요청을 보내고 응답을 받아 처리할 수 있습니다. 가장 일반적인 사용 사례는 환율 정보를 조회하는 함수입니다. 무료 환율 API의 엔드포인트에 요청을 보내고, JSON 형식의 응답을 파싱하여 원하는 통화쌍의 환율을 반환합니다. UrlFetchApp.fetch 메서드에 URL을 전달하면 응답 객체를 얻을 수 있습니다. getContentText 메서드로 응답 본문을 문자열로 추출하고, JSON.parse로 자바스크립트 객체로 변환합니다. 객체의 속성에 접근하여 필요한 데이터를 추출한 후 반환합니다. API 키가 필요한 서비스를 사용할 때는 보안에 주의해야 합니다. 코드에 직접 키를 하드코딩하지 말고, PropertiesService를 활용하여 스크립트 속성에 저장합니다. getScriptProperties().getProperty 메서드로 안전하게 키를 가져와 사용합니다. POST 요청을 보내야 하는 경우도 있습니다. options 객체에 method, contentType, payload 등을 설정하여 복잡한 요청을 구성할 수 있습니다. 헤더를 추가해야 한다면 headers 속성에 객체 형태로 전달합니다. 응답 데이터가 XML 형식일 때는 XmlService를 사용하여 파싱합니다. parse 메서드로 XML 문서를 파싱하고, getRootElement로 루트 요소를 가져온 후 getChild나 getChildren 메서드로 원하는 노드를 탐색합니다. 날씨 정보를 가져오는 함수도 유용합니다. 기상청 API나 OpenWeatherMap 같은 서비스를 활용하여 위치 정보를 입력받아 현재 날씨나 예보를 반환합니다. 주소를 좌표로 변환하는 지오코딩 함수도 구현 가능합니다. Google Maps Geocoding API를 호출하여 주소 문자열을 위도와 경도로 변환하거나 그 반대 작업을 수행합니다. 웹 스크래핑도 제한적으로 가능하지만, 대상 사이트의 이용약관을 확인해야 합니다. HTML을 가져온 후 정규표현식이나 문자열 메서드로 원하는 정보를 추출합니다. 캐싱 전략을 적용하면 API 호출 횟수를 줄이고 성능을 향상시킬 수 있습니다. CacheService를 사용하여 일정 시간 동안 결과를 저장하고, 동일한 요청이 들어오면 캐시된 값을 반환합니다. 타임아웃 설정도 중요합니다. UrlFetchApp.fetch의 옵션에 muteHttpExceptions를 true로 설정하면 HTTP 에러 시에도 예외가 발생하지 않고 응답 객체를 받을 수 있습니다. getResponseCode로 상태 코드를 확인하여 적절히 처리합니다. 비동기 처리가 필요한 경우도 있지만, 커스텀 함수는 동기적으로 작동해야 하므로 복잡한 비동기 로직은 트리거 함수로 분리하는 것이 좋습니다. 외부 라이브러리를 활용하면 개발 시간을 단축할 수 있습니다. Apps Script 라이브러리 저장소에서 유용한 라이브러리를 찾아 프로젝트에 추가하고, 제공되는 함수를 활용합니다. OAuth 인증이 필요한 API를 사용할 때는 Apps Script의 OAuth2 라이브러리를 활용하여 인증 플로우를 구현합니다.
Apps Script로 커스텀 함수 만들 때 성능 최적화와 배열 처리
커스텀 함수를 실무에 적용할 때 가장 중요한 것은 성능입니다. 구글 시트에서 함수가 많은 셀에서 재계산될 때 느려지면 사용자 경험이 크게 저하됩니다. 첫 번째 최적화 원칙은 외부 호출을 최소화하는 것입니다. API 요청이나 데이터베이스 접근은 상당한 시간이 걸리므로, 가능한 한 캐싱을 활용하고 배치 처리를 고려해야 합니다. 두 번째 원칙은 반복문을 효율적으로 사용하는 것입니다. for 루프보다 forEach나 map 같은 배열 메서드가 더 간결하고 가독성이 좋지만, 성능이 중요한 경우 전통적인 for 루프가 더 빠를 수 있습니다. 배열 처리 시 범위 단위로 작업하면 성능이 크게 향상됩니다. 개별 셀을 하나씩 읽고 쓰는 대신, getRange().getValues()로 전체 배열을 한 번에 가져오고, 처리 후 setValues()로 한 번에 기록합니다. 예를 들어 A열의 모든 값을 대문자로 변환하려면, 각 셀마다 함수를 호출하는 대신 배열 전체를 받아 map으로 변환하고 결과 배열을 반환하는 것이 효율적입니다. 이차원 배열을 다룰 때는 행과 열의 구조를 정확히 이해해야 합니다. getValues()는 이차원 배열을 반환하므로, data[row][col] 형식으로 접근합니다. 필터링이나 변환 작업 시 적절한 배열 메서드를 조합하여 사용합니다. 메모이제이션 기법을 적용하면 중복 계산을 피할 수 있습니다. 전역 변수나 객체에 계산 결과를 저장하고, 동일한 입력에 대해서는 저장된 값을 즉시 반환합니다. 정규표현식을 컴파일하여 재사용하는 것도 성능 향상에 도움됩니다. 함수 외부에서 RegExp 객체를 생성하고, 함수 내에서는 test나 exec 메서드만 호출합니다. 불필요한 객체 생성을 줄이는 것도 중요합니다. 루프 내에서 반복적으로 객체를 생성하지 말고, 가능하면 재사용하거나 리터럴 표기법을 사용합니다. 조건문의 순서를 최적화하여 가장 가능성 높은 조건을 먼저 검사하도록 배치합니다. 단락 평가를 활용하여 불필요한 평가를 건너뜁니다. 문자열 연결 시 concat보다는 배열의 join 메서드가 더 효율적입니다. 특히 많은 문자열을 결합할 때 차이가 명확합니다. 함수의 복잡도를 분석하여 O(n) 또는 O(n log n) 수준으로 유지하려고 노력해야 합니다. 중첩 루프로 인한 O(n²) 복잡도는 데이터가 많을 때 심각한 성능 저하를 야기합니다. 에러 핸들링도 성능에 영향을 줄 수 있습니다. try-catch를 과도하게 사용하면 오버헤드가 발생하므로, 예외가 예상되는 특정 부분에만 적용합니다. 로깅도 성능에 영향을 미칩니다. console.log나 Logger.log는 디버깅 시에만 사용하고, 프로덕션 코드에서는 제거하거나 조건부로 실행되도록 설정합니다. 함수 실행 시간을 측정하려면 Date 객체나 console.time을 활용합니다. 시작 시점과 종료 시점의 차이를 계산하여 병목 구간을 식별합니다. 큰 데이터셋을 처리할 때는 페이징이나 스트리밍 방식을 고려합니다. 한 번에 모든 데이터를 로드하지 말고, 필요한 만큼만 점진적으로 처리합니다. 최종적으로 코드 리뷰와 리팩토링을 통해 지속적으로 개선해야 합니다. 중복 코드를 제거하고, 명확한 변수명과 함수명을 사용하여 유지보수성을 높입니다.