발표 영상 소개안녕하세요. 왁타버스 게임즈의 백엔드 팀의 임채성입니다. 이번 글에서는 저희 팀의 오랜 과제였던 '구글 스프레드시트 동기화 메서드'의 리팩터링 과정과 성능 개선 방법을 공유하려고 합니다. 왁타버스 게임즈와 백엔드 팀의 역할먼저 왁타버스 게임즈가 어떤 서비스인지 설명드리고 개발팀에서 달성해야하는 목표를 설명드리겠습니다. 저희 서비스는 유튜버 우왁굳의 메타버스 컨텐츠인 왁타버스의 팬 게임 ⋅ 어플리케이션 플랫폼입니다.팬 게임과 랭킹 그리고 도전과제 등 다양한 기능스프레드 시트로 어드민 페이지로 사용하기 때문에 DB와 데이터 일관성 제공24시간 무중단 운영팬 게임⋅어플리케이션의 랭킹과 다운로드 수 및 조회수 통계 제공이러한 특성들을 고려했을 때 저희팀은 B2B와 디지털 플랫폼 비즈니스로 서류작업..
도입본 케이스는 ORM레벨의 에러 때문에 작성되었기에, ORM에 직접 메서드를 추가하는 접근방식을 사용했습니다.만약 Data Access Layer에 Customized Method를 추가하고 싶으시다면 TypeORM 레퍼지토리를 참조하는 클래스를 구현하세요. TypeORM 커스텀함수가 필요하게 되어 구현하게됐다. 처한 상황은 다음과 같다.발생 환경: MySQL, Mac발생 조건: upsert method를 사용하고 충돌 조건을 PK가 아닌 Key를 사용함결과: upsert signature은 Upsert를 시도한 객체를 반환하는데 ORM에서 객체를 찾지 못해 TypeORM 에러 발생#10909번 이슈 때문에 이를 해결하기 위해 TypeORM에 함수 하나를 추가해보려고 한다. 코드//custom-orm-..
자바 계열에서 넘어오신 분들이 builder 패턴을 통해 인스턴스 생성 전략을 무분별하게 사용하는 경우가 있습니다. 만약, 인자가 많아 빌더패턴을 적용해야한다는 이유는 TypeScript에서는 적절한 이유가 되지 못합니다. TypeScript에서 named parameter 가능하기 때문에 인자가 많다는 이유로는 builder 패턴을 사용할 필요가 없습니다. 코드interface UserProps { nickname: string; email: string; role: UserRoleEnum; deletedAt: Date | null;}export class User extends Entity { private constructor(props: UserProps, id?: UserID) { super(..
이 글은 연산 속도에 관해 이야기하지 않습니다. 단순히 확장성과 용량에 대해서만 이야기합니다. 도입 유저의 권한이라는 요소를 열거형으로 관리할 지 고민하였습니다. 본 글에서는 선택적인 요소를 어떻게 처리하는 것이 좋을지 고민해본 내용을 정리해보려고 합니다. 본문 상세한 설명은 후술. 비교 표: 방식 설명 저장 용량 SMALL INT 저장 용량이 가장 작음, 애플리케이션이 문자열과 매핑해주는 방식 2byte ENUM 확장이 일어나면 DDL이 변경되는 방식, 확실한 무결성 4byte * 가짓수 n = 4n VARCHAR 저장 용량이 큰 방식 (문자열 매핑은 필요없음) 4byte * 길이 n = 4n 별도 테이블 확장에 가장 열려있음. 저장 용량을 가장 많이 차지하는 방식 가장 큼 열거 요소로 enum을 선택..
PostgreSQL에는 Check란? SQL 레벨에서 지원하는 제약조건입니다. (PostgreSQL만 지원하는 것이 아님.) 데이터 insert 요청 시 PostgreSQL DBMS가 값 검증을 수행해주는 제약조건입니다. 다음과 같이 사용할 수 있습니다: CREATE TABLE products ( product_no integer, name text, price numeric CHECK (price > 0) -- 가격 컬럼에 항상 양수만 들어갈 수 있도록 검증 ); Check를 사용하면 이점 애플리케이션에서 값에 대한 검증을 하지 않아도 됨. 서버 코드가 굉장히 간단해짐. 반대로 존재하는 큰 단점 DBMS 마이그레이션 시 검증 기능의 유실됨. 특정 DBMS에 의존하게 됨. (MySQL 8.0.16 이하버..
eslint 수정을 결심하게 된 계기기존의 eslint는 프론트 중심적으로 작성되어있거나, git diff 리딩에 불편하게 되어있어요. 개요tab indent를 4로 변경했어요.javascript는 tab indent를 2로 권장하지만, 백엔드에서는 early return 패턴을 사용하기 때문에 tab depth가 깊어질 일이 없어요.코드 가독성은 향상시키고 node.js 특유의 코드 편집기 우측이 텅텅 비어있는 것을 해결했어요.array, object 구조를 설정했어요.백엔드는 array, object가 길어질 경우가 많은데, 이런 경우 예외처리가 되어있지 않아요.eslint 기능을 사용하여 제약을 걸어 해결했어요.그 외도 코드리딩을 고려해서 작성했어요.git diff를 읽을 때 온점이나 쉼표 혹은 괄..
서론 학교 애플리케이션을 개발 중, 학생증 사본을 통해 학생 인증을 하는 기능을 구현하려고 합니다. 사용 기술: nest.js 9.4.1 node-telegram-bot-api 0.61.0 aws s3, ec2 결과물: 실제 운영되는 프로덕션입니다. 1. telegram 봇 발급 이번에 구현 방식을 조사해보며 telegram을 선택하게 된 이유는 아래와 같다. p2p 방식으로 높은 기밀성 빠르게 개발할 수 있는 개발자 친화적 플랫폼 1. BotFather 검색 후 추가 2. /start 명령어를 입력하여 채팅을 시작해주세요. 3. /newbot 명령어를 입력하여 새로운 봇을 만들어주세요. 4. 봇 이름을 입력해주세요. 네이밍 규칙은 마지막이 bot으로 끝나면 됩니다. (대소문자 무관) 이름이 이미 존재하..
서론 NestJS에서 관계가 묶여있는 여러 테이블에 INSERT를 해야하는 경우가 있습니다. 이 글에서는 TypeORM을 통해 트랜잭션을 관리해보겠습니다. 트랜잭션 관련 글 https://puleugo.tistory.com/142 데이터베이스 트랜잭션이란? 트랜잭션(Transaction) 트랜잭션: 데이터베이스 관리 시스템에서의 최소 상호작용의 단위 개요 데이터베이스 트랜잭션은 데이터베이스에서 수행되는 일련의 작업이며 모두 단일한 논리적 작업 단 puleugo.tistory.com https://puleugo.tistory.com/143 트랜잭션 격리 수준 데이터베이스 트랜잭션 격리 수준 데이터베이스 트랜잭션의 격리 수준은 격리성(각각의 트랜잭션은 서로 간섭없이 독립적으로 수행되어야한다는 규칙)의 견고함..
jest로 테스트코드를 작성하던 도중, it()와 test()의 차이가 궁금해졌다. 결론부터 말하자면, it()와 test()는 같은 함수다. 둘다 jest.It.()를 가르키고 있다. 기능 적으로는 차이가 없으니, 문서를 읽을 때 이를 참고하자. 개인 취향에 따라 사용하면 되고, 가독성을 생각하며 사용하자.
백그라운드 실행은 nohup과 forever이 있지만, nohup은 자동으로 꺼지는 에러를 발견하고 forever을 사용해보려고합니다. Forever은 개발자가 업데이트를 포기한 상황입니다. 새로 개발 하시는 경우에는 Docker, nodemon, pm2를 추천드립니다. 구동환경 Ubuntu 22.04.1 LTS Nest.js 9 Forever 설치 yarn: yarn global add forever npm: npm install -g forever Forever 실행 forever start --minUpdate 1000 --spinSleepTime 1000 -c "yarn start" ./ main.js를 실행했을 때는 DI 쪽으로 에러가 나서 직접 yarn start를 호출하는 방식을 이용했습니다..
$ nest g mo auth Error: Cannot read properties of undefined (reading 'properties') Failed to execute command: node @nestjs/schematics:module --name=auth --no-dry-run --no-skip-import --language="ts" --source-root="src" --spec --no-flat 에러 해결 방법은 2가지가 있는듯하다. @nestjs/schematics 재설치 yarn이라면: yarn global add @nestjs/schematics npm이라면: npm i -g @nestjs/schematics 다만 이 방법으로 해결되지 않았고, 다른 방법을 찾았다. typsc..
정보 Reddit은 공식 REST API, Python 모듈인 PRAW 를 지원합니다. 본 글은 Reddit API를 통한 OAuth 및 게시글 가져오기를 진행하며, 해당 내용을 공부하면서 겪었던 시행착오를 공유합니다. 이번 강의 플로우 레딧 개발자 계정을 생성하고, 앱을 등록합니다. 등록한 앱의 정보와 Reddit 계정을 통해 엑세스 토큰을 얻습니다. 얻은 엑세스 토큰으로 게시글을 얻어옵니다. 어떤 언어에서든 따라할 수 있도록, Postman에서 진행합니다. 1. 레딧 개발자 계정 생성 레딧 계정이 없다면, 회원가입 해줍니다. 구글이나 애플을 통한 OAuth 로그인이 아닌, 이메일을 통한 일반 회원가입으로 진행해주세요. 레딧 개발자 앱 등록을 진행합니다. 아래 사이트에 접속해 로그인해주세요. 레딧 개발..
쿠키와 세션을 함께 설명하는 이유: 이 둘의 특징이 비슷하며 차이점이 명확하기 때문에 비교하면서 배우면 습득하기 편함. 먼저, 개요부터 봅시다. 개요 쿠키란? 쿠키는 브라우저에 휘발성 데이터를 저장하는 방식 세션이란? 세션은 서버에 휘발성 데이터를 저장하는 방식 이 둘은 자주 사용되는 데이터를 빨리 꺼내사용해야 하는 경우 사용됩니다. 세션, 쿠키로 사용하는 이유는 뭘까요? HTTP의 특징 때문입니다. Connectionless(비 연결지향): HTTP의 기본적으로 요청&응답만 하고 끊어버립니다. Stateless(상태정보유지안함): HTTP는 상태정보 저장 안함. 그래서 세션 혹은 쿠키로 데이터를 저장합니다. 쿠키와 세션의 차이 쿠키 세션 저장 위치 브라우저(로컬) 서버 보안성 낮음 높음 수명 반영구 브..
백엔드에서 삭제를 하는 방식은 두가지가 있습니다. 논리 삭제: 저장된 데이터를 사용하지 않아서 논리적으로만 삭제하는 방법 물리 삭제: 저장된 데이터를 실제로 삭제해버리는 방법 그렇다면 왜 논리 삭제를 사용할까요? 이유는 다양합니다. AI 학습 데이터로 사용하기 위함. 주고받은 채팅일 시, 법적인 문제가 생겼을 때 증거로 사용해야 하기 위함. 관계(릴레이션)가 맺어져 있을 때 문제가 생김. 물리 삭제는 위험하며 귀찮은 방식이기 때문에 대부분의 서비스에서 논리 삭제를 이용합니다. 여기까지가 이론이고 이제 코드로 봅시다. TypeORM이 논리 삭제와 물리 삭제를 확인해봅시다. 논리 삭제(soft delete) @Entity('users') export class User { @PrimaryGeneratedCo..
[추천글] 크롤러 성능향상, 이미지 수신 차단 대학교 애플리케이션에 정보시스템의 정보를 크롤링하는 기능을 구현했다. 크롤러는 다른분한테 들은 Node.js 크롤러인 puppeteer을 이용했다. yarn add puppeteer yarn add @types/puppeteer 이 둘을 설치한 후 service에만 puppeteer을 임포트해서 사용할 수 있다. 사용법 https://github.com/puppeteer/puppeteer GitHub - puppeteer/puppeteer: Headless Chrome Node.js API Headless Chrome Node.js API. Contribute to puppeteer/puppeteer development by creating an accou..
헬스 기구 처리 로직 소개 바디로 여러개의 타입 중 하나를 선택해서 입력하는 로직을 구현하고 있었다. 우선, 운동 레퍼지토리는 이렇게 생겼다. 무산소, 유산소 타입의 합집합이다. 이걸 저장하는 방식은 2가지가 있다. 1개의 저장 컨트롤러에 2가지 타입의 DTO를 받는 것. 2개의 저장 컨트롤러를 만들어서 DTO와 1:1로 연결하여 저장하는 것 저는 관리 측면이 편하기 때문에 1번 방식을 이용하기로 했습니다. 여기서 발생한 문제는 스웨거에 어떻게 넣을 것인가.. enum으로 넣으면 터집니다. 하나만 넣으면 문서화 작업의 의미가 사라집니다. 2개의 클래스를 타입으로 사용하면 에러가 납니다. 그래서 어떻게 구현했는데? 구현 방법이 있었습니다. @POST('저장 경로') @ApiOperation({ summar..
e2e 테스트는 매번 데이터베이스를 초기화해줄 필요가 있습니다. 다만.. 저는 Jest를 쓰는데 따로 초기화 해주는 함수가 없었습니다. (있으면 알려주세요!) 그런 이유로 방법 계속 찾아봤는데 따로 메소드를 제공해주지 않아서 팁 정도를 찾아서 이를 공유하고자 합니다. import { Test, TestingModule } from '@nestjs/testing'; import { TypeOrmModule } from '@nestjs/typeorm'; import { Connection } from 'typeorm'; import ormConfig from './orm-config'; import { AppController } from '@app/app.controller'; import { UserMo..
서론 이 글은 2024.02.03일에 업데이트 되었습니다. 클라이언트에서 토큰을 발급받고 발급받은 토큰을 서버로 보내는 방식으로 구현하였었는데 더 효율적이고 안전한 방식으로 개선하였습니다. 본 글보다 우선적으로 읽어야하는 글 https://developers.kakao.com/docs/latest/ko/kakaologin/flutter | 카카오 플러터 문서 https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api | 카카오 로그인 REST API 문서 개요 간단한 흐름 Kakao Developer에 애플리케이션 등록 및 환경설정(Flutter에서 사용할 API 키, Nest.js 서버 주소 등록) Flutter SDK를 이용하여 카카오톡에 OAu..
엔티티를 찾지 못할 때, 발생하는 버그입니다. 저는 테스트코드 작성 중 경로를 잘못 지정했습니다. 엔티티 파일을 찾지 못했을 때 발생합니다. 위가 저한테 발생한 오류이고, 경로는 다음과 같이 설정해주었습니다. 파일 경로는 아래와 같았구요. ┖src ┠app ┖domain ┖equipment ┖entities ┖equipment.entity.ts 해결 방법 위와 같이 사용할 엔티티를 import 해주니 해결되었습니다. +추가 Entity 파일에 @Entity 데코레이터를 적용하지 않았을 때도 발생하니 반드시 확인해주시길 바랍니다. +) 추가 릴레이션 되어 있는 테이블도 import 해주셔야합니다..
NestJS에서 엔티티 위치를 찾을 수 없다는 말입니다. 주로 entity를 찾을 수 없다고 나오지만 이는 "경로 지정이 잘못되었을 때" 나오는 에러입니다. 에러 발생 포인트: 레퍼지토리를 연결하여 CRUD 메소드를 만든 후(Entity 연동 후), Test를 돌려보니 에러가 남. 에러 원인: tsconfig.json과 pakage.json의 모듈 네임 매퍼가 같지 않음. tsconfig.json "jest": { "moduleDirectories": [ "node_modules", "src" ], "moduleFileExtensions": [ "js", "json", "ts" ], "roots": ["","src"], "testRegex": ".*\\.spec\\.ts$", "transform": { ..