CORS Error
Deno
Queue Map

CORS에러와 Deno

Deno 백엔드를 활용하면서 발생한 CORS 에러를 해결한 이야기입니다.

Queue Map

Map으로 Queue를 구현할 수 있습니다.

gopinav / JavaScript-Data-Structures-Tutorial

class Queue {
  #item;
  #head;
  #tail;
  constructor() {
    this.#item = new Map();
    this.#head = 0;
    this.#tail = 0;
  }

  enqueue(val) {
    this.#item.set(this.#tail, val);
    this.#tail += 1;
    return this.length;
  }

  dequeue() {
    if (this.length === 0) return null;

    if (this.length > 0) {
      const result = this.#item.get(this.#head);
      this.#item.delete(this.#head);
      this.#head += 1;
      return result;
    }

    return result;
  }

  get length() {
    return this.#tail - this.#head;
  }
}

처음에 진짜 상수 삽입삭제 시간을 갖게 만들기 위해서 링크드 리스트의 Node로 만들었습니다.

CORS 에러

이미 자주 겪어본 에러인데 이번에는 케이스가 조금 특이합니다. 이번에는 제가 백엔드입니다.

해결은 단순합니다. 하지만 express 버전 말고 deno oak에 맞게 변경하겠습니다.

// main.ts
import { Application } from 'https://deno.land/x/oak@v12.4.0/mod.ts';
import router from './routes/index.ts';
import { oakCors } from 'https://deno.land/x/cors@v1.2.2/mod.ts';

const app = new Application();

app.use(
  oakCors({
    origin: /^.+localhost:(1234|비밀)|https:\/\/비밀\.vercel\.app$/,
  })
);
app.use(router.routes());
app.use(router.allowedMethods());

await app.listen({ port: 8000 });

생각보다 단순하게 해결했습니다. 이렇게 하면 끝입니다.

문제는 .env에 또 추가해줘야 합니다.

chatGPT에게 정규표현식처럼 귀찮은 작업을 시키려고 했는데 생각과 다르게 잘 안 풀렸습니다.

하지만 console.log를 원시인처럼 활용해서 다음처럼 처리했습니다.

# .env
REGEX_ORIGIN=^.+localhost:(1234|비밀)|https:\/\/비밀\.vercel\.app$

양 끝에 슬래시(/)만 지우면 끝이었습니다. 단순하게 생각하면 금방 해결하고 chatGPT 선생님에게 고통받지 않았을 것 같습니다.

import { Application } from 'https://deno.land/x/oak@v12.4.0/mod.ts';
import router from './routes/index.ts';
import { oakCors } from 'https://deno.land/x/cors@v1.2.2/mod.ts';
import { config } from 'https://deno.land/x/dotenv@v3.2.2/mod.ts';

const app = new Application();

const REGEX_ORIGIN = Deno.env.get('REGEX_ORIGIN') || config()['REGEX_ORIGIN'];

app.use(
  oakCors({
    origin: new RegExp(REGEX_ORIGIN),
  })
);
app.use(router.routes());
app.use(router.allowedMethods());

await app.listen({ port: 8000 });

이렇게 처리하니까 동작합니다. 상당히 뿌듯해졌습니다.

다음 의문 관심사는 여기가 맞는가?

진짜 몰라서 하는 질문입니다. 어플리케이션 전체적으로 설정해야 할 것이 여기 위치해야 하는 것은 맞습니다. 하지만 CORS를 설정한다는 코드가 여기 위치해야 하는 것이 독자 입장에서 컨텍스트에 맞는가?

CORS 설정은 웹 애플리케이션의 보안 및 권한 관련 중요한 부분이기 때문에 독자 입장에서는 컨텍스트에 맞는 관심사입니다. 일반적으로 백엔드 애플리케이션에서 CORS 설정을 처리하는 것은 올바른 접근 방식입니다.

- chatGPT

Hallucination인지 검증할 수준의 지식이 없습니다. 하지만 지금 시점에서는 저보다 백엔드 지식이 더 많기 때문에 받아들이겠습니다.

왜 Deno를 활용했는가?

빠르게 학습하고 무료 배포하고자 Deno를 선택했습니다. AWS, Github Action, Docker를 몰라도 deno deploy 서비스로 백엔드 배포가 가능해서 활용했습니다.

작년 10월 이후 백엔드 코드를 처음 작성하기 때문에 가장 쉽게 백엔드를 API를 만들수 있을 것 같아서 선택했습니다.

가장 쉬울 것이라는 가설은 v1.0.0 버전을 배포한 시점에는 적어도 맞습니다.

다른 이유도 있습니다. API 서버를 만들어 배포할 때 무료로 사용하고 싶었습니다.

참고로 AWS, Github Action, Docker를 모르고 사용해도 괜찮지만 알고 사용하면 더욱더 효율적인 백엔드 엔지니어링을 할 수 있습니다.

Deno Deploy 단점

Deno Deploy에서 있는 단점입니다. Worker를 지원하지 않아 일부 API를 활용할 수 없습니다.

이점은 Deno Deploy의 확실한 단점이었습니다.

타입스크립트 설정이 Deno가 기본적으로 제공해주는 것에서 추상화 되어 있습니다. 대부분의 상황에서 장점입니다. 하지만 기본적으로 제공해주는 추상화가 잘 못 설정된 경우도 있었습니다. 대소문자 변경하고 이어서 작업하면 큰 문제는 아니지만 분명 아쉬운 점이었습니다.

Deno의 잠재력

Deno의 잠재력은 엄청납니다. 아직 덜 익숙해서 벤치마크 측정, 테스트 코드 작성 기능을 완전히 활용하지 못했습니다. 테스트 방법을 다시 학습하기는 해야 하지만 기본 설정으로 제공해준다는 점이 상당히 좋았습니다.

테스트 코드를 위해 다른 라이브러리에 의존할 필요가 없습니다.

Deno의 장점

장점은 처음 사용하는 입장에서도 확실히 있었습니다.

url 기반으로 import하기는 엄청난 장점입니다. 패키지 호환성에 대해서 고민은 크게 할 필요가 없었습니다. 이미 Deno 생태계에 추상화 되어 있습니다. Node_module과 패키지 매니저로 고통받는 일은 별로 없었습니다.

왜 백엔드가 필요했는가?

교육과정 이후 지금까지 BaaS만 활용해서 프로젝트를 진행했습니다. 백엔드 엔지니어랑 사이드 프로젝트를 같이 진행해 보는 것도 좋지만 간단한 것은 직접 할 줄 알아야 한다는 생각에 만들었습니다. 엄청나게 복잡한 비즈니스 로직을 구현할 필요는 없지만 백엔드 엔지니어에게 무엇을 요구하고 무엇을 기대해야 하는지 가늠이라도 하고자 직접 했습니다.

BaaS를 사용하면 통신에 대해서 BaaS에서 보통 다 정해줍니다. 하지만 BaaS가 제공하는 통신을 활용해서 테스트 코드를 작성하는 케이스를 못 봤습니다. 보통은 백엔드 엔지니어가 API를 제공하기 전까지 프론트엔드는 Mocking으로 유사 API를 만들고 테스트 케이스도 통신의 성공과 실패까지 포함해서 작성한다고 합니다. 저도 이런 접근으로 백엔드를 직접 구현하기로 했습니다.

레버리지

레버리지는 시간대비 효과입니다.

$$ \text{레버리지} = \frac{\text{생산한 효과}}{\text{투자한 시간}} $$

일을 잘 하는 전략은 레버리지 비율을 높이는 것입니다.

3가지 방법에 집중합니다.

  1. 특정 활동을 완료하는 데 드는 시간 줄이기
  2. 특정 활동의 생산량 늘리기
  3. 레버리지가 높은 활동으로 전환하기

참고로 쉬운 업무가 레버리지 비중이 높은 업무는 아닙니다. 난이도가 높은데 더 높은 수준의 가치를 창출하는 업무도 있습니다.

또 컨텍스트를 자주 바꾸거나 아주 오래 유지하는 것이 레버리지를 높이는 것은 아닙니다.

제가 잘 못하는 것이 있습니다. 뭐 일을 단순하게 생각하는 것도 못하지만 효율적으로 일을 못한다고 스스로 생각합니다. 하루를 반나절처럼 살고 있습니다. 하루를 4일처럼 살고 1주일을 1달처럼 살아도 개발자로서 커리어릴 못하는데 태만하게 취준생 생활을 임하고 있습니다.

래버리지 비중을 높이는 결과를 만들어야 합니다.