Cloud Code는 백엔드 로직이 호출, 데이터 이벤트, 스케줄에 의해 트리거되는 서버 측 함수로 실행되는 서버리스 모델입니다. 이 용어군은 혼란스럽게 쓰이는 경우가 많으므로 두 가지를 먼저 분명히 해 두겠습니다. 첫째, “서버리스”는 서버가 다른 누군가의 문제라는 뜻입니다. 서버는 존재하되, 보이지 않는 곳에서 대신 확장됩니다. 둘째, 함수에는 두 가지 아키텍처가 있습니다. 각 함수가 외부 서비스에 연결된 격리된 단위인 독립형 FaaS와, 이 글의 제목이 가리키는 BaaS 변형, 즉 백엔드 안에 배포되어 자신이 다루는 데이터베이스, 인증, 파일과 같은 환경을 공유하는 함수입니다.
핵심 요약
| 질문 | 답변 |
|---|---|
| 네 가지 속성 | 이벤트 트리거 · 무상태 · 자동 확장 · 사용량 기반 과금 |
| 두 가지 형태 | 독립형 FaaS 단위 vs. 백엔드와 함께 사는 Cloud Code |
| 트리거 계열 | 이름으로 호출 · 데이터 이벤트 · 인증 이벤트 · 스케줄 · 웹훅 |
| 서버 측이어야 하는 이유 | 클라이언트는 디컴파일될 수 있지만 함수는 변조할 수 없음 |
| 솔직한 한계 | 타임아웃, 무상태 제약, 콜드 스타트(0으로 축소되는 경우) |
하나의 함수, 어디서나 호출
고전적인 집계 예제입니다. 데이터 옆에서 계산하고, 답만 전송합니다:
// JavaScript / Node.js — Back4app JS SDK
// Calling a Cloud Code function: server-side logic, one line from the client
const avg = await Parse.Cloud.run('averageStars', { movie: 'Arrival' });
// The aggregation ran NEXT TO the database — only the answer crossed the wire
// The function itself (cloud/main.js — deployed to your backend, not the app):
// Parse.Cloud.define('averageStars', async (req) => {
// const q = new Parse.Query('Review').equalTo('movie', req.params.movie);
// const reviews = await q.find({ useMasterKey: true });
// return reviews.reduce((s, r) => s + r.get('stars'), 0) / reviews.length;
// }); // Flutter / Dart — Back4app Flutter SDK
// Calling a Cloud Code function: server-side logic, one line from the client
final response = await ParseCloudFunction('averageStars')
.execute(parameters: {'movie': 'Arrival'});
final avg = response.result;
// The aggregation ran NEXT TO the database — only the answer crossed the wire
// The function lives in cloud/main.js on your backend — update it anytime;
// every client gets the new logic instantly, no app-store release required. // iOS / Swift — Back4app Swift SDK
// Calling a Cloud Code function: server-side logic, one line from the client
let avg: Double = try await Cloud.run(name: "averageStars",
parameters: ["movie": "Arrival"])
// The aggregation ran NEXT TO the database — only the answer crossed the wire
// The function lives in cloud/main.js on your backend — update it anytime;
// every client gets the new logic instantly, no app-store release required. // Android / Kotlin — Back4app Android SDK
// Calling a Cloud Code function: server-side logic, one line from the client
val params = mapOf("movie" to "Arrival")
val avg = ParseCloud.callFunction<Double>("averageStars", params)
// The aggregation ran NEXT TO the database — only the answer crossed the wire
// The function lives in cloud/main.js on your backend — update it anytime;
// every client gets the new logic instantly, no app-store release required. 리뷰 1,000개의 평균을 휴대폰에서 내려면 리뷰 1,000개를 내려받아야 하지만, 함수 버전은 숫자 하나만 옮깁니다. 이 대역폭 논리는 아래에서 다루는 서버 측 로직의 근거 전체로 일반화됩니다.
트리거 분류
상위에 노출되는 설명 글들은 트리거를 한 문장으로 나열하지만, 이 구조는 표로 정리할 가치가 있습니다:
| 트리거 계열 | 실행 시점 | 대표적인 용도 |
|---|---|---|
| 호출형 함수 | 클라이언트가 JSON 파라미터와 함께 이름으로 호출할 때 | 비즈니스 로직, 집계, 액션 |
| 데이터 트리거 | 클래스의 save, delete, find 전후 | 검증, 기본값, 연쇄 처리, 감사 |
| 인증 트리거 | 로그인 전, 가입/로그아웃 후 | 차단 목록, 환영 플로우, 감사 이벤트 |
| 예약 작업 | cron 표현식 | 리포트, 정리, TTL 삭제, 다이제스트 |
| 수신 웹훅 | 외부 시스템이 이벤트를 POST할 때 | 결제 확인, CI 알림 |
로직이 서버 측에 있어야 하는 이유
대부분의 설명 글에서 빠져 있는 네 가지 근거입니다. 클라이언트를 신뢰하지 않습니다: 앱은 디컴파일되고 요청은 위조됩니다. 기기에서 계산한 가격, 권한 검사, 게임 점수는 제안에 불과하지만, 같은 로직이 함수 안에 있으면 법이 됩니다. beforeSave 트리거는 어느 클라이언트가 보냈든 모든 쓰기를 검증합니다. 시크릿은 서버 밖으로 나가지 않습니다: 서드파티 API 키는 함수의 환경에 머무르며, 누구나 풀어볼 수 있는 번들에는 절대 들어가지 않습니다. API 키 관리 원칙이 구조적으로 보장되는 셈입니다. 릴리스 없이 업데이트합니다: 서버 로직 변경은 모든 사용자에게 즉시 배포되며, 수정과 적용 사이에 앱 스토어 심사 주기가 끼어들지 않습니다. 데이터 가까이에서 계산합니다: 집계, 검색 결과 가공, 팬아웃이 모바일 네트워크 건너편이 아니라 데이터베이스에서 몇 마이크로초 거리에서 실행됩니다.
Cloud Code vs. 독립형 FaaS vs. 컨테이너
| Cloud Code (BaaS 함수) | 독립형 FaaS | 컨테이너 | |
|---|---|---|---|
| 실행 위치 | 백엔드 런타임 내부 | 함수별로 격리된 단위 | 직접 오케스트레이션하는 곳 어디든 |
| 컨텍스트 | 데이터베이스, 인증, ACL이 이미 연결됨 | 모든 서비스를 수동으로 연결 | 직접 구축하는 만큼 |
| 배포 단위 | 코드베이스 하나, 배포 한 번 | 함수별 | 이미지별 |
| 콜드 스타트 | 없음 – 백엔드가 이미 실행 중 | 있음, 0에서 확장할 때 | 0으로 축소할 때만 |
| 특권 작업 | 관리 로직용 마스터 키 접근 | 함수별 IAM 설정 | 자체 인증 체계 |
| 확장 | 백엔드와 함께 | 요청 단위로, 0까지 | 설정한 대로 |
| 적합한 곳 | BaaS 위의 앱 백엔드 | 트래픽이 급증하는 격리된 이벤트 작업 | 장기 실행 상태 유지 서비스 |
서버리스 아키텍처 항목은 이 모델을 폭넓게 다루고, 서비스 사다리에서 FaaS의 위치는 별도의 글이 있습니다. 여기서 중요한 행은 컨텍스트입니다. Cloud Code 함수는 태어날 때부터 연결되어 있습니다. 같은 SDK, 같은 세션 처리 방식, 쿼리에 적용되는 ACL을 갖추고 시작하는 반면, 독립형 FaaS는 모든 프로젝트를 연결 작업부터 시작합니다.
콜드 스타트와 무상태, 솔직하게
요청 단위 확장에서 두 가지 속성이 따라 나오며, 둘 다 분명히 말해 둘 가치가 있습니다. 콜드 스타트는 0으로 축소된 함수가 실행 전에 환경을 초기화해야 할 때 발생합니다. 일반적인 플랫폼에서 수백 밀리초에서 수 초가 걸리고, 최소 웜 인스턴스와 가벼운 번들로 완화할 수 있으며, 항상 실행 중인 백엔드에 호스팅된 함수에서는 아키텍처상 존재하지 않습니다. 이는 벤더의 자랑이 아니라 두 형태 사이의 실질적인 차이입니다. 무상태(stateless)란 계약상 메모리의 어떤 것도 호출 사이에 살아남지 않는다는 뜻입니다. 함수 안에 보관한 카운터, 캐시, 세션은 시한폭탄 같은 버그입니다. 상태는 데이터베이스로 가야 합니다. BaaS 변형의 조용한 장점은, 데이터베이스가 먼저 선택하고 연결하고 보호해야 하는 서비스가 아니라 코드 한 줄 거리에 있다는 점입니다.
일반적인 사용 사례
- 검증과 비즈니스 규칙 – 어느 클라이언트에서 오든 불변 조건을 예외 없이 강제하는
beforeSave게이트. - 집계와 리포트 – 데이터 옆에서 계산하고, 데이터셋이 아닌 답을 반환합니다.
- 서드파티 연동 – 서버에 보관된 시크릿으로 호출하는 결제, 이메일, AI API.
- 웹훅 수신과 발신 – 이벤트 연동의 HTTP 창구 역할을 하는 함수.
- 예약된 유지보수 – cron으로 실행되는 다이제스트, 정리, 삭제 작업. 따로 운영할 워커 서버가 필요 없습니다.
함수로 만들어야 할까? 결정 매트릭스
| 작업 | 적합한 위치 |
|---|---|
| 클라이언트가 변조할 수 있는 로직 | 함수 – 언제나 |
| 급증하는 이벤트 형태의 작업 | 함수 |
| 장시간 연산(수 분 이상) | 함수가 아닌 백그라운드 작업 |
| 상태를 유지하는 상시 서비스(소켓, 큐) | 컨테이너 / 플랫폼 서비스 |
| 지속적으로 매우 큰 볼륨의 지연 민감 핫 패스 | 측정 – 상시 실행 서버가 이길 수 있음 |
| 시크릿을 다루는 모든 것 | 함수 – 시크릿은 절대 클라이언트로 나가지 않음 |
한계와 트레이드오프
- 타임아웃은 계약입니다. 함수는 수 초에서 수 분으로 제한됩니다. 한도를 넘길 수 있는 작업에는 희망이 아니라 작업 큐가 필요합니다.
- 무상태는 엄격합니다. 메모리에 있는 것은 무엇이든 일시적입니다. 이를 잊은 설계는 테스트는 통과하지만 스케일 아웃 상황에서 실패합니다.
- 전형적인 실패 양상은 난립입니다. 공유 모듈과 명명 규칙 없이 흩어진 작은 함수 50개는 도구만 더 나쁜 분산 모놀리스가 됩니다.
- 디버깅은 본질적으로 원격입니다. 브레이크포인트 대신 로그와 트레이스를 씁니다. 로그 환경이 좋은 플랫폼은 여기서 값어치를 합니다.
- 지속 부하에서는 비용이 역전됩니다. 사용량 기반 과금은 급증하는 작업에서는 따라올 것이 없지만, 일정하게 높은 처리량에서는 상시 실행 서버가 더 쌉니다. 브로슈어가 아니라 비용 곡선을 계산해야 합니다.
Back4app에서의 Cloud Code
Back4app은 관리형 데이터베이스, 자동 생성되는 REST 및 GraphQL API, 인증, 파일 스토리지, Cloud Code 서버리스 함수를 결합한 오픈소스 Backend as a Service(BaaS) 플랫폼입니다. 여기서 Cloud Code는 BaaS 형태의 원형 그대로입니다. Back4app 백엔드에 배포되는 JavaScript로, 코드 탭 예제 같은 호출형 함수를 위한 Parse.Cloud.define, 데이터 규칙을 위한 beforeSave/afterSave 트리거, 인증 훅, 예약 작업이 모두 하나의 코드베이스와 한 번의 배포에 담깁니다. 함수는 컨텍스트가 연결된 채 실행됩니다. 클라이언트와 같은 SDK, 쿼리에 적용되는 ACL과 클래스 수준 권한, 관리 로직이 정당하게 이를 우회해야 할 때 쓸 수 있는 마스터 키 접근, 그리고 서버 측 설정에 보관되는 시크릿까지 갖춥니다. 백엔드가 항상 실행 중이므로 0에서 확장하는 콜드 스타트는 결코 적용되지 않습니다. 또한 플랫폼이 오픈소스이므로 함수는 이를 실행하는 어떤 호스트로든 이식할 수 있으며, 이것이 벤더 종속 질문에 대한 실질적인 답입니다.
자주 묻는 질문
서버리스 함수란 무엇입니까?
플랫폼이 HTTP 호출, 데이터 변경, 스케줄 같은 이벤트에 반응해 필요할 때 실행하는 작고 단일 목적의 서버 측 코드 블록입니다. 프로비저닝, 확장, 유지보수는 제공업체가 맡습니다. 개발자는 로직만 배포하고, 이를 실행하는 기반 설비는 플랫폼이 책임집니다.
FaaS와 서버리스의 차이는 무엇입니까?
FaaS(Functions-as-a-Service)는 서버리스의 컴퓨팅 절반으로, 이벤트에 의해 트리거되는 개별 함수를 뜻합니다. 서버리스는 데이터베이스, 인증, 스토리지 같은 관리형 백엔드 서비스(BaaS 절반)까지 포함하는 더 넓은 모델입니다. Cloud Code는 두 절반이 만나는 지점으로, 관리형 백엔드와 함께 실행되는 함수입니다.
서버리스 함수는 어떻게 트리거됩니까?
다섯 계열이 있습니다. 직접 호출(클라이언트나 API가 이름으로 함수를 호출), 데이터베이스 이벤트(저장과 삭제 전후에 실행되는 코드), 인증 이벤트(로그인과 가입에 걸린 훅), 스케줄(cron 방식의 작업), 그리고 외부 시스템에서 들어오는 웹훅입니다. 좋은 플랫폼은 다섯 가지 모두를 인프라가 아니라 등록만으로 제공합니다.
콜드 스타트란 무엇입니까?
0으로 축소되었던 함수를 위해 플랫폼이 새 실행 환경을 초기화해야 할 때 생기는 수백 밀리초에서 수 초의 지연입니다. 최소 웜 인스턴스 유지와 번들 경량화로 완화할 수 있으며, 항상 실행 중인 백엔드에 호스팅된 함수는 0에서 확장하는 경우 자체를 피해 갑니다.
서버리스 함수는 왜 무상태여야 합니까?
병렬로 실행되는 수많은 단명 인스턴스 중 어느 것이든 다음 요청을 처리할 수 있기 때문입니다. 호출 사이에 메모리에 붙들어 둔 값은 언제 사라질지 모르는 버그의 씨앗입니다. 영속 상태는 데이터베이스나 캐시에 둬야 합니다. BaaS 변형에서는 데이터베이스가 이미 연결되어 있으며, 이것이 이 모델이 주는 편의의 큰 부분입니다.
서버리스 함수의 한계는 무엇입니까?
플랫폼은 실행 시간(기본 수 초, 최대 수 분), 메모리, 페이로드 크기를 제한합니다. 장시간 작업은 백그라운드 작업에 속하고, 지속적으로 높은 처리량은 상시 실행 서버보다 비쌀 수 있습니다. 이 한계는 요청 단위 확장의 대가입니다.
서버리스 함수와 마이크로서비스의 차이는 무엇입니까?
축이 다릅니다. 마이크로서비스는 아키텍처를 분해하는 방식이고, 서버리스는 실행 모델입니다. 함수는 마이크로서비스보다 단위가 작으며, 마이크로서비스는 함수, 컨테이너, 모놀리스의 한 조각 중 무엇으로도 구현할 수 있습니다. 컨테이너로는 제어권과 장기 실행 프로세스를 얻고, 함수로는 운영 부담이 없는 환경과 요청 단위 확장을 얻습니다.
서버리스 함수는 벤더 종속(vendor lock-in)을 유발합니까?
폐쇄형 플랫폼에서는 독자적인 이벤트 형식과 도구가 실질적인 결합을 만듭니다. 이에 맞서는 것이 오픈소스입니다. 어떤 Node.js 호스트에서도 실행되는 Back4app의 오픈소스 Cloud Code처럼 열린 런타임을 대상으로 작성한 함수는 한 클라우드의 이벤트 체계에 묶이는 대신 백엔드와 함께 이동합니다.