내가 직접 AWS 배포 도구를 만든 이유

발행: (2026년 2월 18일 오전 02:40 GMT+9)
12 분 소요
원문: Dev.to

Source: Dev.to

번역을 진행하려면 번역하고자 하는 전체 텍스트를 제공해 주세요. 텍스트를 주시면 요청하신 대로 한국어로 번역해 드리겠습니다.

My Journey to Building a Faster Serverless Deployment Tool

저는 12년 이상 다양한 언어와 팀, 수십 개 프로젝트를 경험한 소프트웨어 엔지니어입니다. 제가 하는 일을 사랑하고, 깔끔한 도구로 실제 문제를 해결하는 데 매력을 느낍니다.

The Problem

  • Serverless on AWS – 저는 Serverless FrameworkAWS CDK를 사용해 서버리스 애플리케이션을 구축해 온 경험이 있습니다.
  • Friction – 아이디어를 떠올리고 클라우드에 배포하기까지의 간극이 생각보다 크게 느껴졌습니다.
  • CloudFormation bottlenecks – 배포마다 CloudFormation이 차이점(diff)을 계산하고, 계획을 세우고, 변경을 적용하는 데 기다려야 했습니다. 한 줄짜리 코드 수정에도 마찬가지였습니다. 민첩함이 핵심인 서버리스 환경에서는 마치 닻을 내린 듯한 느낌이었습니다.

Inspiration from Other Clouds

  • Google Cloud / Firebase – Firebase의 개발자 경험에 감명받았습니다: 코드에 함수를 정의하고, CLI 한 줄로 실행하면 모든 것이 배포됩니다.
  • Why AWS still wins – AWS Lambda는 더 간단해 보였습니다(컨테이너 빌드 없이, 빠른 콜드 스타트) 그리고 “모든 곳에 컨테이너” 접근 방식보다 제 사고 모델에 더 잘 맞았습니다.

The Idea

“Firebase의 code‑as‑config 모델을 직접 AWS SDK 호출과 결합해 CloudFormation을 완전히 건너뛰자.”

Lambda 핸들러를 작성하고, 그 코드 옆에 바로 설정을 선언한 뒤, 하나의 명령으로 모든 것을 배포할 수 있다면—CloudFormation 템플릿도, 스택 정의도, 번들러 설정도, IAM 보일러플레이트도 없이—원하던 빠른 피드백 루프를 얻을 수 있을 것입니다.

Core Challenges

  1. State reconciliation – CloudFormation이 하는 일을 재현: 현재 AWS 상태와 원하는 상태를 비교하고 차이를 동기화하되, 직접 SDK 호출만 사용합니다.
  2. Type‑safe orchestration – API 호출, 오류 처리, 동시성을 관리하면서 코드베이스가 통제 불능으로 흐트러지는 것을 방지합니다.

The Three Libraries That Made It Possible

Library왜 도움이 되었는가
ts‑morphTypeScript AST를 분석해 핸들러 코드에서 인프라 정보를 직접 추출할 수 있게 해줍니다(별도의 YAML/JSON 필요 없음).
Effect‑TS함수형 효과 시스템을 제공해 API 호출을 조율하고, 오류를 처리하며, 강력한 타입 안전성을 갖춘 동시성 관리를 가능하게 합니다.
Typed AWS SDK wrapper (my own)AWS SDK 소스의 JSDoc을 기반으로 Effect‑랩핑된 SDK 호출을 생성하고, 완전한 타입 지정 오류 처리를 제공합니다.

이 도구들을 활용해 effortless‑aws를 만들었습니다.

Design Goals

  • Single‑object configuration – 모든 핸들러는 하나의 옵션 객체(path, method, handler logic, dependencies, parameters 등)를 받는 단일 함수 호출입니다. 커리드 함수나 빌더 체인이 없습니다.
  • Context & DI via Effect‑TS – 핸들러는 Lambda 레벨에서 컨텍스트 팩터리를 선언하고, 이는 모든 요청 핸들러에 컴파일 타임 보장을 통해 주입됩니다.
  • Type‑checked dependencies – 다른 리소스(예: DynamoDB 테이블)가 필요한 핸들러는 deps 필드만 추가하면 시스템이 자동으로 연결해 줍니다.

Minimal Handler Example

import { defineHttp } from "effortless-aws";

export const hello = defineHttp({
  method: "GET",
  path: "/hello",
  onRequest: async ({ req }) => ({
    status: 200,
    body: { message: "Hello World!" },
  }),
});

그것이 바로 Lambda 함수, API‑Gateway 라우트, IAM 역할을 모두 한 파일에 담은 모습입니다.
eff deploy를 실행하면 바로 라이브됩니다.

Comparison: CDK vs. Effortless‑AWS

CDK – Creating a Simple HTTP Endpoint with a DynamoDB Table

// CDK: stack definition (separate file)
const table = new dynamodb.Table(this, "Orders", {
  partitionKey: { name: "id", type: dynamodb.AttributeType.STRING },
  billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
});

const fn = new nodejs.NodejsFunction(this, "GetOrders", {
  entry: "src/handlers/get-orders.ts",
  runtime: lambda.Runtime.NODEJS_20_X,
  environment: { TABLE_NAME: table.tableName },
  bundling: { /* … */ },
});
  • Multiple files – Stack definition, function definition, and bundling config are all separate.
  • CloudFormation – Deployments wait for diff/plan/execute cycles.
  • Boilerplate – IAM roles, permissions, and resource references must be wired manually.

Effortless‑AWS – Same Outcome in One Place

import { defineHttp } from "effortless-aws";

export const getOrders = defineHttp({
  method: "GET",
  path: "/orders",
  deps: {
    table: {
      name: "Orders",
      partitionKey: "id",
      billingMode: "PAY_PER_REQUEST",
    },
  },
  onRequest: async ({ deps }) => {
    const items = await deps.table.scan().items();
    return { status: 200, body: items };
  },
});
  • Single file – Handler, API route, DynamoDB table, and IAM permissions are declared together.
  • No CloudFormation – Direct SDK calls make deployment near‑instant.
  • Zero boilerplate – The framework infers IAM policies and wiring from the deps object.

Takeaways

  • Skipping CloudFormation for serverless workloads can shave minutes (or even seconds) off the feedback loop.
  • A code‑as‑config approach, powered by TypeScript AST analysis and a strong effect system, gives you the developer experience of Firebase on AWS.
  • With proper type‑level guarantees, you can keep the flexibility of raw SDK calls without the chaos of manual wiring.

That’s the story of why I finally snapped and built my own deployment tool – effortless‑aws – and how it solves the pain points I faced with Serverless Framework, CDK, and CloudFormation.

CDK를 사용한 인프라 (비교용)

fy: true, sourceMap: true },
});

table.grantReadData(fn);

const api = new apigateway.HttpApi(this, "Api");
api.addRoutes({
  path: "/orders",
  methods: [apigateway.HttpMethod.GET],
  integration: new HttpLambdaIntegration("GetOrdersIntegration", fn),
});

그것은 단지 인프라일 뿐입니다. 핸들러 파일, 스택 연결, 앱 진입점, 그리고 CloudFormation을 사용한 cdk deploy가 아직 필요합니다.

effortless‑aws 로 동일하게

“한 파일. 한 명령.”

// That's it. One file.
import { defineHttp, defineTable } from "effortless-aws";

export const orders = defineTable({
  pk: "id",
});

export const getOrders = defineHttp({
  method: "GET",
  path: "/orders",
  deps: { orders },
  onRequest: async ({ deps }) => {
    const items = await deps.orders.scan();
    return { status: 200, body: items };
  },
});

실행:

eff deploy

완료. 테이블, 함수, 라우트, IAM 권한이 모두 몇 초 만에 생성됩니다.

Source:

eff deploy 작동 방식

eff deploy네 단계를 거칩니다. 이 단계들을 조율하는 것이 프로젝트에서 가장 어려운 부분이었는데, 각 단계가 다음 단계에 연결되고 오류가 어디서든 발생할 수 있으며, 리소스들이 서로 의존하기 때문입니다. Effect‑TS 덕분에 이를 관리할 수 있었으며, 전체 파이프라인을 구성 가능하게 만들고, 각 단계는 독립적으로 사고할 수 있는 Effect가 됩니다.

1. 코드 분석 (ts‑morph)

  • ts‑morph는 TypeScript 소스를 읽어 defineHttp / defineTable 호출을 모두 추출합니다 — 메서드, 경로, 의존성, 파라미터, 정적 파일 — 모두 AST에서 직접 가져옵니다.
  • 이는 별도의 YAML/JSON 설정 파일을 대체하며, 코드 자체가 진실의 출처가 됩니다.

2. 번들링 (esbuild)

  • esbuild는 각 핸들러를 단일 ESM 파일로 컴파일합니다.
  • 동일한 node_modules가 모든 Lambda ZIP에 중복 포함되는 것을 방지하기 위해, 공유 의존성은 Lambda Layer에 배치합니다 (프로젝트 전체에 하나의 레이어).
  • 각 핸들러는 깔끔한 단일 JS 파일로 번들링되고, 레이어가 런타임에 node_modules를 제공합니다.
  • 현재까지 pnpm 프로젝트와도 안정적으로 동작합니다.

3. 상태 비교

  • 도구는 AWS에 이미 존재하는 리소스를 확인하고, 코드가 선언한 내용과 비교합니다.
  • 차이점만 적용됩니다 — 본질적으로 CloudFormation이 하는 일과 비슷하지만, 프로비저닝 엔진 오버헤드가 없습니다.
  • 가장 큰 개념적 난관은 적절한 비교 granularity를 찾고, 멱등성을 보장하는 업데이트를 구현하는 것이었습니다.

4. 리소스 프로비저닝 (AWS SDK + Effect‑TS)

  • 직접적인 AWS SDK 호출을 통해 리소스(Lambda 함수, DynamoDB 테이블, API Gateway 라우트, IAM 정책)를 생성, 업데이트 또는 재구성합니다.
  • 모든 AWS 호출은 타입이 지정된 Effect 래퍼를 통해 이루어지므로, 가능한 모든 오류가 사전에 알려집니다.
    • 함수가 이미 존재하면 → 로그를 남기고 계속 진행.
    • 내부 AWS 오류가 발생하면 → 배포를 중단.

프로젝트 상태

  • effortless‑aws는 현재 알파 단계입니다.
  • 이미 프로덕션에서 사용되고 있습니다:
    • 문서 웹사이트.
    • Lambda 함수, DynamoDB 테이블, 스트림 및 트리거를 사용하는 개인 프로젝트.
  • 모든 것이 배포되고 실행되지만, 아직 다듬어야 할 부분이 남아 있으며 활발히 개발 중입니다.

로드맵

  • 새로운 핸들러 (예: S3 정적 웹사이트, EventBridge).
  • 개선된 diff 알고리즘.
  • 더 나은 TypeScript 사용성.

설치 및 리소스

npm install effortless-aws
  • GitHub:
  • 웹사이트 및 문서:

프로젝트 구축에 사용된 도구들

도구목적
Effect‑TSTypeScript용 타입이 지정된 함수형 프로그래밍
ts‑morphTypeScript AST 분석 및 조작
esbuild빠른 JavaScript/TypeScript 번들러
AWS SDK for JavaScript (v3)공식 AWS SDK
Typed AWS SDK wrapperAWS SDK에 대한 타입이 지정된 오류를 포함한 Effect 래퍼
0 조회
Back to Blog

관련 글

더 보기 »