1. Supabase 소개

Build in a weekend Scale to millions

Supabase is an open source Firebase alternative.

postgres에 붙어서 rest api를 제공하는 https://docs.postgrest.org/ 를 애플리케이션 개발자가 쉽게 사용할 수 있도록 얇은 레이어를 제공하는게 supabase다. 일종의 플랫폼도 운영하고 있어서 개발자가 supabase 관련 인프라에 대한 고민 없이 애플리케이션 개발에 집중할 수 있다.

2년 전부터 개인 블로그 백엔드를 supabase로 사용하고 있었고, 이번에 AESK 서비스를 구현하면서 supabase를 상용 제품에 사용해볼 수 있었다. supabase를 사용하면서 높은 생산성과 굉장히 만족스러운 개발자 경험을 했기 때문에 이를 공유해서 회사의 전체 생산성을 높이기 위해 세미나를 열었다.

1-1. Nextjs와 Supabase로 구현한 AESK 서비스 둘러보기

간단..

github 링크 추가. Supabase를 사용하게 되면 예시코드로 사용 가능.

2. 다이어그램

Nextjs Frontend (얇음)
--------------
Nextjs Backend (두꺼움, 대부분의 비즈니스 로직 담당)
==============
Supabase (얇음, PostgreSQL을 위한 인터페이스 제공 및 인증 담당, Produre와 View로 일부 비즈니스 로직 담당)
--------------
PostgreSQL (두꺼움)

3. 데이터베이스 모델링

데이터베이스 스키마만 설계하면 Supabase가 타입스크립트 타입을 자동으로 생성해준다. 이 타입을 프론트엔드에서 적극적으로 사용하면 편하다.

데이터베이스 스키마 형상관리도 기본으로 지원함.

supabase client에서 기가막히게 타입 추론을 해준다

  • select * from ~
  • select explicit_columns from ~

3-1. 1:1, 1:N, M:N 연관관계

스키마에 foreign key를 달아놓으면 supabase client에서 알아서 처리하고 타입추론도 해준다.

  • select *, joined_table(*) from ~
  • select *, joined_table(explicit_columns) from ~

JPA의 목적 중 하나는 관계 연산 패러다임의 결과를 객체지향 패러다임에 맞게 변환하는 것.

자바는 객체를 파일로 저장하는 직렬화 기능과 저장된 파일을 객체로 복구하는 역 직렬화 기능은 지원한다. 하지만 이 방법은 직렬화된 객체를 검색하기 어렵다는 문제가 있으므로 현실성이 없다. 현실적인 대안은 관계형 데이터베이스에 객체를 저장하는 것인데, 관계형 데이터베이스는 데이터 중심으로 구조화되어 있고, 집합적인 사고를 요구한다. 그리고 객체지향에서 이야기하는 추상화, 상속, 다형성 같은 개념이 없다.

객체와 관계형 데이터베이스는 지향하는 목적이 서로 다르므로 둘의 기능과 표현 방법도 다르다. 이것을 객체와 관계형 데이터베이스의 패러다임 불일치 문제라 한다. 따라서 객체 구조를 테이블 구조에 저장하는 데는 한계가 있다.

애플리케이션은 자바라는 객체지향 언어로 개발하고 데이터는 관계형 데이터베이스에 저장해야 한다면, 패러다임의 불일치 문제를 개발자가 중간에서 해결해야 한다. 문제는 이런 객체와 관계형 데이터베이스 사이의 패러다임 불일치 문제를 해결하는 데 너무 많은 시간과 코드를 소비하는 데 있다.

김영한, <자바 ORM 표준 JPA 프로그래밍>, p40, 2015, 에이콘

JPA는 직접 자바 객체로 엔티티 모델링을 하고 애노테이션으로 연관관계를 명시해줘야 하지만, supabase는 이 패러다임 변환을 자동으로 해준다(자바로 엔티티 모델링하고 연관관계 명시하고 의도한대로 연관관계 매핑 잘 되는지 테스트 작성하고… 그 고생하는 시간이 사라진다!!).

예)

SELECT A.id, A.name, B.id AS expert_career_id, B.company_name  
FROM public.expert A  
         JOIN public.expert_career B ON A.id = B.expert_id  
WHERE B.company_name IN ('sdf', 'afaf');

위 쿼리의 결과는 다음과 같다.

id,name,expert_career_id,company_name
19,김수봉,195,sdf
2,수정,249,sdf
2,수정,248,afaf

id 2번의 행이 2개, 총 3개의 행이 나온다.

supabase는 위 결과를 객체 패러다임에 맞게 아래처럼 알아서 변환한다. 연관관계를 array로 묶어준다.

const {data} = await supabase
  .from('expert')
  .select('id,name,expert_career(id,company_name)')
  .in('expert_career.company_name', ['sdf', 'afaf']);
[{
  id: 19,
  name: '김수봉',
  expert_career: [{
    id: 195,
    company_name: 'sdf'
  }]
},{
  id: 2,
  name: '수정',
  expert_career: [{
    id: 249,
    company_name: 'sdf'
  },{
    id: 248,
    company_name: 'afaf'
  }]
}]

3. 보안 및 권한 관리

  • anon key
  • service key
  • Row Level Security
    • RLS를 제대로 활용하진 않았음.. 아직 불편하다. 굳이?? 같은 느낌.

4. 사용하면서 만든 컨벤션

  • 스키마 변경사항은 항상 형상관리를 한다. 마이그레이션 스크립트를 통해서만 스키마를 변경한다.
  • 테이블의 모든 컬럼에 comment를 달아 설명을 추가한다.
  • 비즈니스 로직은 최대한 Nextjs Backend에
    • 프론트엔드에서 생성하는 supabase client에는 anon_key만 노출한다. service_key를 프론트엔드에서 사용하면 절대 안 된다.
  • form은 브라우저의 기본 form 사용 (https://www.robinwieruch.de/next-forms/)
    • validation도 서버에서 한다.
    • 실시간으로 validate해야 할 때만 프론트엔드에서 validate

5. 사용례

  • CRUD
    • 최신 Nextjs의 form사용
      • react-hook-form등의 프론트엔드 form 라이브러리를 사용하지 않고 good old days에 사용하던 브라우저 기본 form을 사용한다. 근-본
  • 복잡한 쿼리 (검색 등)
  • 클라이언트 사이드에서 렌더링할 때 서버 호출이 필요한 경우
    • Nextjs의 server action을 사용하면 API 구현 없이 서버에 일을 시킬 수 있음.
  • 로깅 및 알림
    • Vercel에 서드파티 로깅 SaaS를 붙여서 사용한다 (아직 안 해봄)

6. 한계

  • supabase client에서 트랜잭션을 지원하지 않는다.
    • 트랜잭션이 필요하면 데이터베이스 프로시저를 활용한다.
    • postgres에 직접 연결해서 트랜잭션을 구현할 수 있음
      • prisma, drizzle등의 ORM을 사용할 수도 있다.
  • id,password 회원가입을 사용할 때 id에 이메일만 사용할 수 있다.
    • 이를 우회하기 위해 Nextjs 백엔드에서 supabase를 통하지 않고 postgres에 쿼리를 직접 보냈다.

7. +a Supabase로 서버리스 백엔드 만들기

7.1 Nextjs로 배포

아직 해보진 않았지만 기술적으로 충분히 가능해보인다.

express같은 웹프레임워크 대신 Nextjs를 사용해서 백엔드 엔드포인트를 만든다.

AWS를 직접 사용해서 백엔드를 구축할 때보다 인프라 관련 노동을 덜 해도 됨 + supabase에서 제공하는 데이터베이스 타입생성 기능을 이용해서 엔티티 모델링을 빠르게 할 수 있음. 중소규모 프로젝트에서 시도해보면 좋을 것 같다.

문서는?

7.2 Supabase Edge Functions로 배포

Nextjs를 통하지 않고 supabase에서 운영하는 edge function으로 백엔드 로직을 배포할 수도 있음.

아직 써보진 않았지만.. Deno를 사용하던데, Nextjs에서 쓰기 위해 작성한 타입스크립트 코드도 공유해서 쓸 수 있지 않을지?

결론

  1. BaaS를 사용하기 때문에 백엔드 개발자가 인프라를 구축하는 시간이 큰 폭으로 줄어든다.
    1. Object Storage, Message Queue, Cron Job 등도 Supabase를 통해서 해결
  2. 자동 생성된 데이터베이스 모델과 타입 레벨 프로그래밍이 가져오는 혁신
    1. 관계형 테이블을 객체로 매핑하는 작업이 사라진다. 자동 생성된 모델을 애플리케이션의 모든 곳에서 사용하면 됨.
    2. 타입스크립트가 제공하는 컴파일타임의 어마어마한 타입 추론 기능 덕분에 걱정없이 사용할 수 있다.
  3. Supabase Edge Functions 혹은 Vercel Functions를 사용해서 Serverless Backend 구현 가능
    1. API 개발도 충분히 가능하다.
  4. Supabase Client만으로 해결하기 힘든 문제는 직접 postgres에 연결해서 해결할 수 있다.
    1. prisma, drizzle등의 ORM 사용 가능.
    2. ID에 email밖에 쓸 수 없는 문제도 supabase를 우회하고 postgres와 직접 통신해서 해결한다.
  5. 프로젝트 초반에는 Supabase로 빠르게 개발하고, 더 이상 Supabase가 감당할 수 없을 정도로 커졌을 때 AWS등으로 migration하는 전략을 사용하면 회사의 생산성을 많이 높일 수 있을 것 같다.
    1. Supabase는 얇은 레이어고 Postgres가 본체이기 때문에 Aurora Postgres등을 사용하면 낮은 비용으로 마이그레이션이 가능할 것으로 예상.