AI로 만든 앱에도 진짜 백엔드가 필요할까? 추가하기 전에 확인해야 할 것들

진짜 백엔드가 필요한 경우는 정확히 세 가지뿐입니다 — 결제를 처리할 때, API 키와 비밀 정보를 브라우저 밖에 보관해야 할 때, 그리고 여러 사용자가 동시에 같은 데이터를 수정할 때 유일한 진실의 원천 역할을 해야 할 때입니다.

의문이 스멀스멀 올라오는 순간

백엔드란 그저 브라우저가 아닌 다른 곳에서 실행되는 코드일 뿐입니다 — 브라우저가 해서는 안 되는 일, 예를 들어 결제를 처리하거나 비밀 정보를 보관하는 일을 하고, 데이터베이스와 대화를 나눕니다. AI로 만든 앱 대부분은 이미 이런 일의 일부를 하고 있습니다. 여러분이 상상하던 모습과 다르게 생겼을 뿐이죠.

앱은 잘 돌아갑니다. 사용자들이 가입하고, 기능들이 하나씩 출시됩니다. 그러다 문득 이런 찜찜한 느낌이 스멀스멀 올라옵니다. “진짜 백엔드”가 있어야 하지 않을까? 다들 백엔드 이야기를 하니까요. 진지한 앱에는 백엔드가 있으니까요. 여러분의 빌더는 React 안에 TypeScript가 들어간 무언가를 만들어줬는데, 이게 뭔가… 프로페셔널하지 않은 것 같다는 생각이 들기 시작합니다.

진실을 말씀드리자면, 그 느낌은 대체로 틀렸습니다. 백엔드가 하는 일 중 마법 같은 건 하나도 없고, 여러분의 AI로 만든 앱은 이미 그 일을 하고 있을 가능성이 큽니다. 만약 하고 있지 않다면, 백엔드를 추가한다고 해서 진짜 문제가 — 실제로 고장 난 무언가가 — 해결되지는 않습니다.

이 글은 그 차이를 구별하는 법에 관한 이야기입니다.

백엔드는 대체 무엇을 위해 존재하는가?

백엔드가 존재하는 이유는 정확히 세 가지입니다: 돈을 처리하는 일, 비밀 정보를 안전하게 지키는 일, 그리고 두 명 이상이 같은 데이터를 수정할 때 유일한 진실의 원천 역할을 하는 일.

돈을 처리하는 일. 여러분의 앱이 결제를 받거나 사용자에게 요금을 청구한다면, 결제 처리업체는 반드시 백엔드를 요구합니다. 브라우저에서 시크릿 API 키를 가지고 Stripe에 직접 요청을 보낼 수는 없습니다(그 키를 클라이언트 사이드 코드에 넣는 셈이 되어, 앱을 쓰는 누구나 볼 수 있게 되니까요). 그래서 키를 안전하게 보관하고, 브라우저의 요청을 받아, 사용자를 대신해 Stripe와 대화할 서버가 필요합니다. 그게 백엔드입니다. 거창할 필요는 없습니다 — 대부분의 앱에는 Node 함수 하나면 충분합니다 — 하지만 존재는 해야 합니다.

비밀 정보를 안전하게 지키는 일. API 키, 데이터베이스 비밀번호, 인증 토큰 — 이런 것들은 브라우저에 둘 수 없습니다. 앱을 사용하는 누구나 읽을 수 있기 때문이죠. AI로 만든 앱이 인증이 필요한 외부 서비스를 호출해야 한다면, 브라우저 혼자서는 할 수 없습니다. 대신 앱은 여러분의 백엔드와 대화하고, 백엔드가 키를 가지고 있다가 외부 서비스를 호출합니다. 비밀 정보는 계속 비밀로 남습니다.

데이터의 단일 진실 원천. 두 사용자가 동시에 앱을 쓰면서 둘 다 같은 데이터를 바꾸려 한다면, 누구의 변경이 이기는지 결정할 중앙 권한이 필요합니다. 브라우저는 심판 역할을 할 수 없습니다 — 두 브라우저는 서로를 볼 수 없으니까요. 그래서 “앨리스의 이름 변경이 적용되고, 밥의 요청은 30밀리초 늦게 들어왔으니 적용되지 않는다”라고 말해줄 서버가 필요합니다. 그 서버가 바로 백엔드입니다. 데이터베이스 섹션이 중요한 이유도 여기에 있습니다 — 모든 데이터가 실제로 존재하는 한 곳이 필요합니다.

목록에 없는 것들을 눈여겨보세요: 성능, 프로페셔널함, 확장성, “다들 있으니까”. 이런 것들은 여러분에게 필요 없는 복잡함을 더하도록 유혹하는 느낌들입니다.

정말로 백엔드가 필요한지 어떻게 알 수 있을까?

세 가지 신호가 진짜 백엔드가 필요하다는 뜻입니다: 브라우저 혼자서는 고칠 수 없는 이유로 앱이 느릴 때, 사용자가 볼 수도 방해할 수도 없는 곳에서 코드가 실행되어야 할 때, 그리고 두 사용자가 서로의 데이터를 덮어쓰고 있을 때. 지금부터 이 중 어느 것이 여러분의 상황에 해당하는지 판단하는 법을 알려드리겠습니다.

“느려요.” 사용자들이 느리다고 이야기한다면, 문제는 보통 세 가지 중 하나입니다: 브라우저가 일을 너무 많이 하고 있거나(CPU 부담, 나쁜 알고리즘, DOM을 과도하게 렌더링), 네트워크가 느리거나(안타깝지만 사실입니다), 데이터베이스가 느리거나(쿼리가 너무 많거나, 인덱스가 잘못됐거나 — 여러분의 AI로 만든 앱은 이미 데이터베이스와 대화하고 있고, 대체로 괜찮은 데이터베이스입니다). 진짜 백엔드는 브라우저의 CPU 작업을 고쳐주지 않습니다. 진짜 백엔드는 네트워크 지연도 고쳐주지 않습니다(물리 법칙은 어쩔 수 없으니까요). 백엔드는 캐싱이나 더 똑똑한 쿼리 패턴을 더해 데이터베이스 쿼리를 도와줄 수는 있지만, 여러분의 빌더는 이미 그 부분을 생각해뒀을 가능성이 높습니다.

실제 느림에 관한 이야기 하나: 어떤 할 일 목록 앱이 목록을 불러올 때 굼떴습니다. 개발자는 “진짜 백엔드가 필요해”라고 생각했죠. 하지만 진짜 문제는, 앱이 매번 5,000개의 할 일 전체를 불러오고 있었다는 점이었습니다. 처음 50개만 불러오고 “더 보기” 버튼을 다는 대신 말이죠. 백엔드는 건드리지도 않고 오후 한나절 만에 고쳤습니다. 백엔드는 문제가 아니었던 겁니다.

“사용자가 보지 못하게 코드를 실행하고 싶어요.” 이건 실제로 말이 되는 유일한 이유이지만, 생각보다 드문 경우입니다. 예를 들면: 사용자가 가입한 뒤 이메일을 보내는 일(탭을 닫아도 그 코드는 계속 실행되어야 하니까요), 밤새 파일을 처리하는 백그라운드 작업, 일정에 따라 외부 API를 호출하는 일. 이런 것들은 타당한 이유입니다. 어딘가의 서버에서 실행되는 무언가가 필요하긴 합니다. 하지만 인증과 라우팅과 데이터베이스를 갖춘 완전한 백엔드일 필요는 없습니다. 일정에 따라 실행되거나 웹훅으로 호출되는 단일 “클라우드 함수”면 충분합니다. 백엔드 전체보다 훨씬 간단하죠.

“여러 사용자가 동시에 같은 데이터를 바꾸고 있고, 변경 내용이 사라지고 있어요.” 이건 진짜 문제입니다. “앨리스의 수정 내용이 사라졌어요”라거나 “두 사람이 같은 폼을 수정했는데 두 번째 사람의 변경이 첫 번째를 덮어썼어요” 같은 상황을 보고 있다면, 경합(contention) 문제를 겪고 있는 겁니다. 어떤 데이터베이스는 이런 상황을 다른 데이터베이스보다 잘 처리하고, AI 빌더 중에는 이런 처리에 약한 데이터베이스를 기본값으로 쓰는 경우도 있습니다. 하지만 해결책이 항상 백엔드 전체는 아닙니다 — 데이터베이스를 바꾸거나, 잠금(locking)을 추가하거나, 낙관적 동시성 제어(옛 버전 번호를 기억해뒀다가 업데이트 전에 비교하는 방식을 그럴싸하게 부르는 말)를 추가하는 것일 수도 있습니다. 빌더에게 데이터베이스를 바꾸거나 버전 추적을 추가할 수 있는지 물어보세요. 백엔드가 아니라 더 똑똑한 데이터베이스 설정이 필요한 걸지도 모릅니다.

백엔드 문제처럼 보이지만 사실은 아닌 것들

백엔드 문제로 오해받지만 실제로는 아닌 것 세 가지가 있습니다: JavaScript가 한 곳에 모여 있다는 점, 별도의 API 레이어가 없다는 점, 그리고 구체적인 문제 없이 막연히 보안이 걱정된다는 점.

“코드가 전부 JavaScript고 한 곳에 모여 있어요.” 성공한 앱들 중 상당수는 브라우저 안의 JavaScript가 진짜 데이터베이스(Firebase, Supabase, MongoDB Atlas 등 여러분의 빌더가 설정해준 무엇이든)와 대화하는 구조입니다. “진짜 백엔드” 서버가 따로 없어도 모든 게 잘 돌아갑니다. 코드가 한 언어로 한 곳에 모여 있다고 해서 진짜가 아닌 건 아닙니다. JavaScript는 잘 작동합니다.

“별도의 API 레이어가 없어요.” 여러분의 브라우저가 데이터베이스와 직접 대화하고 있습니다. 많은 사람들의 첫 반응은 “이건 뭔가 잘못됐어, 중간에 API가 있어야 해”입니다. 하지만 만약 그 API가 그저 “이 테이블에서 select해서 반환한다”거나 “이 테이블에 insert한다” 정도라면, 중간 레이어는 아무것도 더해주지 않습니다. 그저 오버헤드일 뿐이죠. 여러분의 데이터베이스는 이미 그 자체로 API입니다. 할 수 있다면 직접 호출하세요.

“보안이 걱정돼요.” AI로 만든 앱 대부분은 합리적인 기본값을 갖추고 있습니다: 비밀번호는 해시 처리되고, SQL 인젝션은 불가능하며(데이터베이스 라이브러리가 막아줍니다), 비밀 정보는 클라이언트 밖에 보관됩니다. 정말로 걱정된다면 해야 할 일은 빌더에게 이런 것들을 제대로 하고 있는지 물어보는 것이지, 반사적으로 백엔드를 추가하는 게 아닙니다. 부실하게 만든 백엔드는 잘 만든 프론트엔드보다 더 취약합니다.

솔직한 판단 흐름도

추측 없이 이 문제를 판단하는 방법입니다:

  1. 백엔드 없이도 앱이 지금 하는 일을 할 수 있나요? 그렇다면 2번으로. 아니라면 여러분은 이미 백엔드를 가지고 있거나(혹은 만들어야 하는 상황입니다). 계속 진행하세요. (여러분의 AI로 만든 앱에는 이미 백엔드가 있을 수도 있습니다.)

  2. 추가하려는 그 기능이 브라우저가 근본적으로 할 수 없는 일인가요? 결제를 받는 일? 확실히 그렇습니다. 이메일을 보내는 일? 맞습니다. 시크릿 키로 외부 API를 호출하는 일? 그렇습니다. 그 외의 것은요? 대체로 아닙니다. 브라우저가 할 수는 있지만 느린 게 문제라면 3번으로. 브라우저가 할 수 없는 일이라면 백엔드가 필요합니다.

  3. 실제 문제를 고치면 느림이 사라지나요? 불러오는 걸 줄인다든지, 더 똑똑하게 캐싱한다든지, 요청을 묶어서 처리한다든지, 더 나은 데이터베이스를 쓴다든지. 핵심은 무엇이 실제로 느린지를 먼저 파악하는 것입니다. 뻔한 해결책을 다 시도해본 뒤에야 백엔드를 추가하세요. 백엔드를 추가한다고 느린 알고리즘이 고쳐지는 게 아니라, 그저 다른 기계로 옮겨질 뿐이니까요.

  4. 백엔드를 추가하면 실제로 문제가 해결되나요? 이게 함정입니다. “성능을 개선하겠다”며 백엔드를 추가했더니 지연이 오히려 더 심해지는 경우가 있습니다. 이제 여러분의 백엔드로 네트워크 호출을 하고, 그 백엔드가 다시 데이터베이스로 네트워크 호출을 하기 때문이죠. 브라우저에서 한 번의 호출로 끝냈을 수도 있는 일인데 말입니다. 먼저 측정하고, 그다음에 추가하세요.

완전한 백엔드가 필요한가, 클라우드 함수 하나면 충분한가?

원하는 것이 몇 초간 실행되다 멈추는 함수 하나에 들어간다면, 완전한 백엔드가 아니라 클라우드 함수가 필요한 겁니다. 다음은 간단한 판별법입니다.

백엔드가 해줬으면 하는 일을 떠올려보세요. 그리고 그걸 호출되면 몇 초간 실행되다 멈추는 단일 JavaScript 함수(대략 100줄 정도)로 작성한다고 상상해보세요. 그 안에 다 들어갈까요?

  • 결제 웹훅을 처리하는 일? 됩니다.
  • 환영 이메일을 보내는 일? 됩니다.
  • 업로드 전에 파일을 검증하는 일? 됩니다.
  • 매일 밤 리포트를 실행하는 일? 됩니다(어느 정도는요 — 일정에 맞춰 호출하면 됩니다).

답이 “된다”라면, “진짜 백엔드”는 필요 없습니다. 클라우드 함수가 필요합니다. Vercel이든, AWS Lambda든, Google Cloud Functions든 뭐든 좋습니다. 더 저렴하고, 더 간단하고, 서버를 돌보지 않아도 됩니다.

답이 “안 된다”라면 — 뭔가가 항상 실행되고 있어야 하고, 수천 건의 요청을 처리해야 하고, 복잡한 비즈니스 로직이 있어야 한다면 — 그때는 진짜 백엔드를 고민할 때이고, 그 대화가 훨씬 중요해집니다. 하지만 솔직히 말해, AI로 앱을 만드는 사람들에게 이런 경우는 드뭅니다. “백엔드 작업”처럼 보이는 것 대부분은 그저 “이 API를 호출한다”거나 “이 데이터를 저장한다”는 것이고, 여러분의 빌더는 이미 이런 걸 처리하고 있을 가능성이 큽니다.

빌더에게 물어봐야 할 진짜 질문

무언가를 추가하기 전에, 빌더에게 딱 하나만 물어보세요: 지금 무엇이 고장 났고, 백엔드가 그걸 실제로 고쳐줄까?

만약 구체적인 답이 있다면 — “돈을 청구해야 한다”, “시크릿 키로 API를 호출해야 한다”, “데이터 경합이 있다” — 좋습니다. 무엇을 향해 만들어가고 있는지 알고 있는 겁니다.

만약 답이 “음, 진짜 앱에는 백엔드가 있으니까요”라면, 그건 이유가 아니라 느낌입니다. 아무도 공유하지 않는 앱에 사용자 계정을 추가하고 싶어지게 만드는 느낌, 실제로는 세 가지밖에 없는데 열다섯 개짜리 테이블로 이루어진 데이터베이스 스키마를 만들고 싶어지게 만드는 느낌과 똑같습니다. 그건 스코프 크리프(scope creep)의 냄새가 백엔드라는 모자를 쓰고 나타난 것뿐입니다.

성공한 1인 앱 대부분에는 여러분이 상상하는 의미의 “진짜 백엔드”가 없습니다. 데이터베이스는 있습니다(빌더가 이미 설정해뒀을 겁니다). 일정에 따라 실행되는 함수 한두 개는 있을 수도 있습니다. 하지만 실제 일을 하는 건 브라우저에서 실행되는 코드이고, 그 코드가 데이터베이스와 직접 대화하며, 중간 레이어 없이 기능을 출시합니다.

여러분의 앱은 지금 그대로도 아마 괜찮을 겁니다. 그렇지 않다는 느낌은 대개 진실의 소리가 아니라 야망의 소리입니다. 실제 문제를 해결할 때 백엔드를 추가하세요. 그래야 할 것 같은 느낌이 들어서가 아니라요.


다음에 기능을 구상할 때는 이렇게 물어보세요: 이건 브라우저가 근본적으로 할 수 없는 일인가? 아니면 그저 그 단어를 너무 많이 들어서 백엔드가 필요하다고 생각하는 것뿐인가? 이 두 질문에 대한 답은 서로 다르고, 그중 여러분이 결정할 몫은 하나뿐입니다.