개발하면서 알게된 것들

프록시, 리버스 프록시

드라마 "참교육" 보다가 리버스 프록시라는 개념이 나왔다.

∴ 프록시는 사용자를 숨기고, 리버스 프록시는 서버를 숨긴다.

ORM

쿼리 작성없이 DB 조작을 가능하게 하는 것 → 직관적으로 관리할 수 있음

Index in Table

테이블의 특정 컬럼을 빠르게 찾기 위한 색인 구조이다.

다음을 위해 사용한다:

이를 사용하면:

하지만 단점이 있는데:

다음 상황에서 주로 사용한다:

Index가 많아지면 왜 느려지는 걸까?

테이블 데이터만 바꾸는 게 아니라, 관련된 인덱스 구조도 같이 갱신해야 하기 때문이다.

즉, 인덱스가 없으면 주로 테이블 한 곳만 건드리면 되는데 인덱스로 인해서 테이블 + 인덱스를 동시에 수정해야 하기 때문이다.

또한, 인덱스는 보통 B-Tree 같은 구조라서:

∴ 조회는 빨라지지만 업데이트 시 인덱스도 함께 관리해야 하기 때문에 성능이 느려질 수 있다.

테이블 파티셔닝

Analytics 서비스 만들다가 생긴 궁금증에서 출발: → 이벤트 데이터를 하나의 테이블로만 관리하면 데이터가 늘어날 수록 조회 성능이 느려질텐데 어떻게 관리하는 걸까?

1억 행의 events → 이 상태에서 데이터를 가져오게 된다면 엄청난 양의 데이터를 뒤져야 한다.

테이블 파티셔닝은 하나의 큰 테이블을 특정 기준에 따라 여러 개의 물리적 파티션으로 나누어 저장하는 방식이다.

events              ← 부모 테이블
├── events_2026_08  ← 파티션
├── events_2026_09  ← 파티션
└── events_2026_10  ← 파티션

여러 테이블이 실제로 존재하지만, 어플리케이션에서는 하나의 테이블처럼 사용하고 DB는 조건에 맞는 파티션만 조회한다.

select * from events;
insert into events (...) values (...);

이를 사용하면:

멀티 테넌시

하나의 애플리케이션이 여러 고객이나 조직(테넌트)을 함께 서비스하는 구조를 말한다.

예를 들어, 사용자가 어떤 조직에 속할 수 있는 기능이 있고 해당 조직만 접근할 수 있는 페이지 및 기능이 있다면 멀티 테넌시이다. → 슬랙의 채널과 노션의 조직 페이지

Cloudflare Assets

웹사이트의 정적 파일을 올려두고 빠르게 보여주는 기능이다. (CDN을 이용하는 정적 파일 배포) 빌드 결과물의 HTML, CSS, JavaScript, 이미지, 폰트가 대상이며, Cloudflare가 전 세계 가까운 서버에서 캐시해 전달한다. 즉, API 서버가 이미지·JS 파일까지 직접 처리하지 않게 해 주는 “사이트 파일 배포·전달 담당”이라고 볼 수 있다.

반면, 사용자 업로드 파일(이미지, 비디오)과 같은 것은 보통 Assets 보다는 R2가 적합하다. R2와 Assets 모두 CDN를 활용한다는 것은 동일하지만, 두 서비스는 타겟이 다르다.

Monorepo

packages의 역할

둘 이상에서 쓰거나 독립적으로 관리할 가치가 있는 코드를 모아두는 공간이다. 예를 들어 백엔드와 프론트엔드 사이의 API 계약 관련 코드를 packages로 관리하면 진실 원천이 하나가 되기 때문에 수정과 관리에 용이하다.

다만, 항상 공용으로 사용하는 코드만 packages로 두는 것은 아니고, 설령 하나의 앱만 사용하더라도 “서비스 규칙을 담는 곳”으로 사용할 수도 있다. 즉, packages가 **"모듈"**로서의 역할도 하는 것이다. (책임을 분리하고, 서로 함부로 의존하지 못하게 하려고 분리)

catalog의 역할

모노레포 안에서 여러 패키지가 같은 의존성 버전을 공유하게 하는 기능이다.

루트 package.json:

{
  "workspaces": {
    "packages": ["apps/*", "packages/*"],
    "catalog": {
      "typescript": "^5.8.3",
      "zod": "^3.25.0"
    }
  }
}

하위 패키지:

{
  "dependencies": {
    "zod": "catalog:"
  },
  "devDependencies": {
    "typescript": "catalog:"
  }
}

이렇게 하면 여러 패키지의 zod, typescript 의 버전을 각각 적지 않고 루트에서 한 번만 관리할 수 있다. (catalog를 사용하지 않으면 공통으로 사용함에도 불구하고 매번 패키지마다 버전을 관리해줘야 하는 불편함을 겪게 된다.)

그룹별로도 나눌 수 있는데, 그룹이란 일종의 역할로 보면 된다. (역할 예시: 테스트, UI, 인증 등등)

{
  "catalogs": {
    "testing": {
      "vitest": "^3.0.0"
    }
  }
}
{
  "devDependencies": {
    "vitest": "catalog:testing"
  }
}

이때, 그룹별로 나눠 관리한다면 catalogs 를 사용해야 한다. 위 예시는 catalog 목록 중에서 vitest는 testing 그룹으로 분리함을 명시한다.