728x90
반응형

  • 클라우드 프론트란?
AWS CloudFront는 콘텐츠를 빠르고 안전하게 전달하기 위한 콘텐츠 전송 네트워크(Content Delivery Network, CDN) 서비스입니다.

 

  • 주요 역활과 기능
전송 속도 최적화 CloudFront는 전 세계에 분산된 엣지 로케이션(Edge Location)을 활용해 사용자와 가까운 서버에서 콘텐츠를 제공합니다.
캐싱(Content Caching) CloudFront는 자주 요청되는 콘텐츠를 엣지 로케이션에 캐싱하여 원본 서버로의 요청을 줄입니다.
보안 강화 CloudFront는 AWS의 보안 도구와 통합되어 데이터와 애플리케이션을 보호합니다.
실시간 콘텐츠 제공 CloudFront는 실시간 스트리밍과 동적 콘텐츠 제공을 지원합니다.
통합 및 확장성 CloudFront는 AWS의 다른 서비스와 원활하게 통합되며 확장성이 뛰어납니다.
비용 효율성 사용자가 가까운 엣지 로케이션에서 콘텐츠를 받기 때문에 네트워크 비용이 줄어들고, 사용량 기반 과금으로 필요에 따라 비용이 조정됩니다.

 

  • 왜 AWS의 CloudFront인가요?

본 프로젝트는 사용자가 비디오를 업로드 하고, 그걸 모두가 볼수있는 영상플렛폼 만들기 입니다.

가장 큰 이유는 위에서 설명드린 통합 및 확장성 때문이라고 할 수 있겠습니다.
AWS CloudFront와 기타 CDN 서비스(Akamai, Cloudflare, Google Cloud CDN)를 비교했을 때, 각각의 서비스가 제공하는 장점과 단점을 고려해야 합니다. 하지만
장단점을 고려하기 앞서서, 개발 시간과 개발 난이도 또한 비용이라고 할 수 있단 점을 인지하고 비교해보면 답을 얻을 수 있습니다.
저희 프로젝트는 이미 AWS의 S3와 람다와 같은 AWS생태계를 사용하고 있습니다.
AWS CloudFront는 AWS 서비스와의 통합이 원활하지만, 다른 클라우드 서비스(Akamai, Cloudflare, Google Cloud CDN)와의 통합은 제한될 수 있습니다. 여기서  "통합이 제한될 수 있다"는 리스크는 시간이 그만큼 소요 될 수있다는거고 비용적 리스크로 이어집니다.
 
쉽게 이야기해서 위의 사진을 보면, 이미 AWS생태계를 구축했는데 특별한 이유도 없이 타사의 CDN서비스를 선택하는것 자체가 리스크가 될 수 있기 때문입니다.

 


영상을 클라이언트가 다운로드 해서 시청하는 방식이 아닌 s3에 저장된 m3u8파일을 활용해서 스트리밍 형식으로 전송하기 위해서 클라우드 프론트는 효과적인 선택지라고 할 수 있습니다.

728x90
반응형
728x90
반응형

자동화를 위한 CI/CD 워크플로우

1. GitHub Actions에서 ECR 리포지토리 자동 생성

GitHub Actions에서 AWS CLI 명령을 실행하여 ECR 리포지토리가 없는 경우 자동으로 생성하도록 설정합니다.

2. Docker 이미지 빌드, 태그, 푸시 자동화

GitHub Actions가 코드를 푸시할 때 Docker 이미지를 빌드하고 태그를 자동으로 생성한 뒤, AWS ECR에 푸시하도록 구성합니다.

3. ECS 배포 자동화

AWS CLI 명령어를 통해 ECS에 Task Definition을 자동으로 등록하고, 서비스 업데이트까지 진행되도록 설정합니다.

 


자동화된 GitHub Actions 워크플로우

 

프로젝트 디렉토리 경로
.github/workflows/deploy.yml

name: CI/CD Pipeline

# 1. 워크플로우 트리거 설정
# main 브랜치에 코드가 푸시될 때만 이 워크플로우가 실행됩니다.
on:
  push:
    branches:
      - main  # main 브랜치에 푸시될 때 실행

jobs:
  deploy:
    runs-on: ubuntu-latest  # 이 작업은 Ubuntu 최신 버전에서 실행됩니다.

    steps:
    # 2. GitHub 리포지토리에서 코드 체크아웃
    # 깃허브 리포지토리의 코드를 가져옵니다.
    - name: Checkout code
      uses: actions/checkout@v3

    # 3. AWS CLI 구성
    # AWS 리소스와 상호작용하기 위해 AWS CLI를 설정합니다.
    - name: Configure AWS CLI
      uses: aws-actions/configure-aws-credentials@v2
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}  # 깃허브 액션의 Secrets에 AWS Access Key를 저장해야 함.
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}  # 깃허브 액션의 Secrets에 AWS Secret Key를 저장해야 함.
        aws-region: ap-northeast-2  # 사용할 AWS 리전 (예: 서울 리전)

    # 4. ECR 리포지토리 확인 및 생성
    # Docker 이미지를 저장할 ECR 리포지토리가 존재하지 않을 경우 생성합니다.
    - name: Create ECR repository if not exists
      run: |
        REPO_NAME=my-app  # 사용할 ECR 리포지토리 이름을 정의합니다.
        # 리포지토리가 있는지 확인하고, 없으면 생성
        aws ecr describe-repositories --repository-names $REPO_NAME || \
        aws ecr create-repository --repository-name $REPO_NAME

    # 5. Amazon ECR 로그인
    # AWS ECR에 Docker CLI를 통해 로그인합니다.
    - name: Log in to Amazon ECR
      run: |
        aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin <account-id>.dkr.ecr.ap-northeast-2.amazonaws.com
        # `<account-id>` 부분에 AWS 계정 ID를 작성해야 합니다.

    # 6. Docker 이미지 빌드 및 ECR 푸시
    # 로컬에서 Docker 이미지를 빌드하고 ECR에 푸시합니다.
    - name: Build and push Docker image
      run: |
        IMAGE_URI=<account-id>.dkr.ecr.ap-northeast-2.amazonaws.com/my-app:latest  # 푸시할 이미지의 URI
        docker build -t my-app .  # Docker 이미지 빌드
        docker tag my-app:latest $IMAGE_URI  # Docker 이미지에 태그 추가
        docker push $IMAGE_URI  # ECR에 Docker 이미지 푸시
        # `<account-id>` 부분에 AWS 계정 ID를 작성해야 합니다.

    # 7. ECS 배포
    # 새로운 Task Definition을 등록하고 ECS 서비스를 업데이트합니다.
    - name: Deploy to ECS
      run: |
        CLUSTER_NAME=my-app-cluster  # ECS 클러스터 이름
        SERVICE_NAME=my-app-service  # ECS 서비스 이름
        TASK_FAMILY=my-app-task  # ECS Task Definition 패밀리 이름

        # 기존 Task Definition 가져오기
        TASK_DEFINITION=$(aws ecs describe-task-definition --task-definition $TASK_FAMILY)

        # Task Definition에 새로운 Docker 이미지 URI 반영
        NEW_TASK_DEFINITION=$(echo $TASK_DEFINITION | jq --arg IMAGE_URI $IMAGE_URI \
          '.taskDefinition | .containerDefinitions[0].image = $IMAGE_URI | del(.status,.taskDefinitionArn,.revision,.requiresAttributes,.compatibilities)')

        # 새로운 Task Definition JSON 파일로 저장
        echo $NEW_TASK_DEFINITION > new-task-definition.json

        # 새 Task Definition 등록 및 ARN 저장
        TASK_ARN=$(aws ecs register-task-definition --cli-input-json file://new-task-definition.json --query 'taskDefinition.taskDefinitionArn' --output text)

        # ECS 서비스 업데이트
        aws ecs update-service --cluster $CLUSTER_NAME --service $SERVICE_NAME --task-definition $TASK_ARN
        # Task Definition의 ARN이 서비스에 반영되며 새로운 컨테이너를 실행합니다.

Secrets 설정

  1. AWS_ACCESS_KEY_ID와 AWS_SECRET_ACCESS_KEY를 GitHub Secrets에 추가:
    • GitHub 리포지토리 > Settings > Secrets and variables > Actions로 이동.
    • New repository secret 클릭 후 아래 키-값 쌍 추가:
      • AWS_ACCESS_KEY_ID: AWS Access Key
      • AWS_SECRET_ACCESS_KEY: AWS Secret Key

ECR 설정

  • <account-id>: AWS 계정 ID를 ECR URI에 반영해야 합니다. 예를 들어:
123456789012.dkr.ecr.ap-northeast-2.amazonaws.com
  • REPO_NAME: ECR 리포지토리 이름입니다. 위 예제에서는 my-app으로 지정.

ECS 설정

  • CLUSTER_NAME: ECS 클러스터 이름입니다. (예: my-app-cluster)
  • SERVICE_NAME: ECS 서비스 이름입니다. (예: my-app-service)
  • TASK_FAMILY: ECS Task Definition 이름입니다. (예: my-app-task)

Docker 이미지 태그

  • IMAGE_URI: AWS ECR에 푸시할 이미지의 URI입니다.
    • 형식: <account-id>.dkr.ecr.<region>.amazonaws.com/<repository-name>:<tag>
    • 예: 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/my-app:latest
728x90
반응형
728x90
반응형

Multer는 Node.js를 위한 미들웨어로, 다중 파트(Multipart) 데이터를 처리하는 데 사용됩니다. 특히 파일 업로드와 관련해 매우 유용하며, Nest.js에서도 쉽게 통합할 수 있습니다. 아래는 Multer에 대한 개념 정리와 Nest.js 프로젝트에 적용하는 방법에 대한 예시입니다.


Multer의 개념

Multer란?

  • Multipart/form-data: HTML form 태그로 전송되는 파일 데이터를 처리하기 위한 포맷입니다. 일반적으로 파일 업로드에 사용됩니다.
  • Multer: Express.js 기반의 미들웨어로, HTTP 요청에서 multipart/form-data 데이터를 처리하는 데 특화되어 있습니다.

Multer의 주요 기능

  1. 파일 저장 위치:
    • 메모리(memoryStorage): 파일이 버퍼에 저장됩니다.
    • 디스크(diskStorage): 서버의 디스크에 파일이 저장됩니다.
  2. 파일 필터링:
    • 업로드할 파일의 유형(예: 이미지, 텍스트 파일 등)을 제한할 수 있습니다.
  3. 이름 지정:
    • 업로드된 파일의 이름을 제어할 수 있습니다.
  4. 제한 설정:
    • 업로드 파일 크기, 개수 등을 제한할 수 있습니다.
    •  

Multer를 Nest.js 프로젝트에 적용하기

1. Multer 설치

Nest.js에서 Multer를 사용하려면 관련 패키지를 설치해야 합니다:

npm install --save @nestjs/platform-express multer

2. Controller 구현

Multer를 사용하여 파일 업로드를 처리하는 컨트롤러를 작성합니다.

import { Controller, Post, UseInterceptors, UploadedFile } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import { extname } from 'path';

@Controller('upload')
export class UploadController {
  @Post()
  @UseInterceptors(
    FileInterceptor('file', {
      storage: diskStorage({
        destination: './uploads', // 파일 저장 경로
        filename: (req, file, callback) => {
          // 파일 이름 설정: 현재 시간 + 확장자
          const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
          const ext = extname(file.originalname);
          callback(null, `${uniqueSuffix}${ext}`);
        },
      }),
      limits: {
        fileSize: 5 * 1024 * 1024, // 최대 파일 크기: 5MB
      },
      fileFilter: (req, file, callback) => {
        if (!file.mimetype.match(/\/(jpg|jpeg|png|gif)$/)) {
          return callback(new Error('Only image files are allowed!'), false);
        }
        callback(null, true);
      },
    }),
  )
  uploadFile(@UploadedFile() file: Express.Multer.File) {
    console.log('Uploaded file:', file);
    return {
      message: 'File uploaded successfully!',
      file: file,
    };
  }
}

3. Module 설정

컨트롤러를 모듈에 등록합니다.
upload.module.ts

import { Module } from '@nestjs/common';
import { UploadController } from './upload.controller';

@Module({
  controllers: [UploadController],
})
export class UploadModule {}

 

app.module.ts

UploadModule을 메인 모듈에 포함시킵니다.

import { Module } from '@nestjs/common';
import { UploadModule } from './upload/upload.module';

@Module({
  imports: [UploadModule],
})
export class AppModule {}

4. 폴더 생성

업로드된 파일을 저장할 디렉토리를 생성합니다. 프로젝트 루트에 uploads 폴더를 만들어야 합니다:

/final-Project
  ├── src
  │     ├── app.module.ts
  │     ├── upload
  │           ├── upload.controller.ts
  │           ├── upload.module.ts
  ├── uploads    <-- 업로드된 파일 저장 디렉토리

 

728x90
반응형
728x90
반응형

주요 라이브러리:

  • libavcodec: 비디오 및 오디오 코덱에 대한 인코딩 및 디코딩 기능 제공
  • libavformat: 미디어 파일 형식을 다루는 기능 제공
  • libswscale: 이미지 및 비디오의 크기 조절과 색 공간 변환 기능 제공
  • libswresample: 오디오 리샘플링 및 포맷 변환 기능 제공
  • libavfilter: 비디오와 오디오 필터링 기능 제공

다양한 포맷간의 변환, 인코딩, 디코딩, 필터링, 스트리밍 등 여러 작업을 지원

 

공식 문서에서 다양한 설명 제공

import { Injectable } from '@nestjs/common';
import { exec } from 'child_process';  // 'child_process' 모듈을 사용하여 FFmpeg 명령어를 실행
import { promisify } from 'util';  // exec을 Promise 기반으로 사용하기 위해 promisify 사용

const execPromise = promisify(exec);  // exec을 Promise 방식으로 변환

@Injectable()
export class VideoService {
  // 영상 자르기 함수
  async cutVideo(inputPath: string, startTime: string, endTime: string, outputPath: string): Promise<string> {
    try {
    
    
    
      // FFmpeg 명령어 생성
      // -i: 입력 파일 경로
      // -ss: 시작 시간
      // -to: 종료 시간
      // -c copy: 비디오와 오디오 스트림을 복사하여 빠르게 처리
      // outputPath: 자른 후 저장할 파일 경로
      const command = `ffmpeg -i ${원본영상경로로} -ss ${시작 시간} -to ${종료 시간} -c copy ${저장할 경로}`;
      
      
      
      // 명령어 실행
      const { stdout, stderr } = await execPromise(command);
      //execPromise(command)는 Node.js의 child_process.exec을 Promise 기반으로 감싼 버전입니다.
	  //command는 실행할 FFmpeg 명령어로, 이 명령어는 영상 자르기 작업을 수행하게 됩니다.
      
      
      
      
      console.log('FFmpeg Output:', stdout);  // FFmpeg 실행 결과 출력
      if (stderr) {
        console.error('FFmpeg Error:', stderr);  // FFmpeg 에러 메시지 출력
      }



      // 작업 성공 시 반환 메시지
      return `Video cut successfully from ${startTime} to ${endTime}. Output: ${outputPath}`;
    } catch (error) {
      console.error('Error cutting video:', error);  // 에러 발생 시 로그 출력
      throw new Error('Failed to cut video');  // 에러 발생 시 예외 처리
    }
  }
}
728x90
반응형
728x90
반응형
 
1일차: 프로젝트 주제 선정

오늘은 팀원들과 함께 프로젝트 주제를 정하는 시간을 가졌습니다. 여러 아이디어가 나왔지만, 결국 모두가 흥미를 느끼고 참여할 수 있는 주제로 합의했어요. 주제에 맞춰 요즘 많은 회사들이 사용하는 최신 기술 스택들을 조사하고, 이번 프로젝트에 적절히 녹여낼 계획입니다. 이를 통해 우리 프로젝트가 실무적인 트렌드도 반영할 수 있도록 하려고 해요.
1일차) 협업툴**노션**을 활용해서 프로젝트 계획하기


2일차: 필요한 기능 정의와 기술 스택 정리

**노션**페이지에 필요한 기능들 정리

오늘은 우리가 정한 주제에 맞춰서 필요한 기능들을 정의하고, 각 기능을 구현하기 위해 어떤 기술이 필요한지 분석해봤어요. 이 과정에서 각 기능마다 필요한 라이브러리나 프레임워크도 함께 정리했는데, 무작정 사용하기보다는 그 필요성을 꼼꼼히 따져보려고 해요.

 

왜 따져봐야 할까요.

 

라이브러리나 프레임워크는 프로젝트의 속도를 올릴 수 있지만, 너무 많이 쓰면 오히려 코드가 복잡해지고 관리도 어려워져요. 그래서 꼭 필요한 경우에만 사용하기로 했습니다. 필요한 경우에는 이걸 왜 쓰는지, 장점은 무엇인지, 사용하지 않으면 어떤 점이 불편해질지까지 생각해보면, 시간이나 비용 면에서도 더 나은 선택을 할 수 있을 것 같거든요.

노션에 이 모든 내용들을 정리해서 앞으로도 참고하려고 해요.


 

영상 편집 에디터 페이지 구현 고려

이번 프로젝트에서 영상을 주제로 다루다 보니, 사용자 경험을 높이기 위해 영상 편집 에디터 페이지를 구현할 수 있을지 고민하게 되었어요. 그 과정에서 가장 필요한 프레임워크로 FFmpeg가 있다는걸 발견했습니다.

 

FFmpeg는 다양한 라이브러리를 제공하여 영상 편집 기능을 구현하는 데 큰 도움을 줄 수 있습니다. 주요 라이브러리로는 다음이 있어요:

  • libavcodec: 비디오와 오디오 코덱의 인코딩 및 디코딩 기능을 제공
  • libavformat: 다양한 미디어 파일 형식을 다루는 기능 제공
  • libswscale: 이미지와 비디오의 크기 조절 및 색 공간 변환 기능 제공
  • libswresample: 오디오 리샘플링 및 포맷 변환 기능 제공
  • libavfilter: 비디오와 오디오 필터링을 위한 기능 제공

이 라이브러리들을 잘 활용하면 영상 편집 에디터 페이지도 충분히 구현할 수 있을 것 같아요. 다음 게시글에서는 FFmpeg의 자세한 기능과 사용법에 대해 다루면서, 어떻게 프로젝트에 적용할 수 있을지 구체적으로 살펴보겠습니다!

728x90
반응형
728x90
반응형

이번 프로젝트에서는 다양한 협업툴을 사용하여 효율적으로 작업을 진행할 예정입니다. 주요 협업툴로는 깃허브, 라이브쉐어, , 노션 등이 있습니다. 그 중 오늘은 **노션(Notion)** 을 어떤식으로 사용해서 프로젝트를 진행할 것인지에 대해
이야기 해보려합니다.

우선 노션 홈페이지에서 체인트 투게더라는 팀명으로 페이지를 만들었습니다.


1. 노션을 통한 협업 계획 

**노션(Notion)**을 활용해서 팀 내 기획, 회의록, 와이어프레임, API 명세서, ERD 작성 등 다양한 문서 작업을 체계적으로 관리할 예정입니다. 이를 활용하여 프로젝트 전반의 흐름을 관리하고, 각 구성원들이 실시간으로 업데이트와 수정 사항을 공유할 수 있습니다.


2. 노션 활용 분야

  • 기획: 10초 길이의 짧은 영상을 올리고 볼수있는 틱톡?같은 웹페이지를 만들기로 했습니다

  • 회의록 작성: 매일 회의를 시작할 시간을 정하고, 노션에 회의록을 남겨 모든 팀원들이 언제든지 회의 내용을 쉽게 확인할 수 있도록 했습니다.

  • 와이어프레임: 저희는 피그마를 사용해서 초기 UI/UX 디자인을 도식화하여 프로젝트의 방향성을 잡았습니다.

  • 기술 스택 및 기능 정리: 개발에 필요한 기술 스택과 주요 기능들을 정리하여 팀원들이 어떤 기술을 사용하고 어떤 기능을 개발해야 하는지 명확히 정리할 예정입니다

이 외에도

  • API 명세서: 프로젝트에 필요한 API의 설계와 규격을 명확히 정리할수 있습니다.
  • ERD: 데이터베이스 설계를 시각적으로 정리하여 데이터 구조를 명확히 합니다.
  • 개발 목표 캘린더: 프로젝트의 일정을 관리하고, 각 목표를 달성할 수 있는 계획을 수립합니다.

이러한 모든 내용들은 노션에 정리하고, 이를 바탕으로 본격적인 개발을 시작할 예정입니다.

노션을 사용하면 프로젝트의 전반적인 내용을 한 곳에 모을 수 있어, 개발을 진행하면서 언제든지 필요한 정보를 쉽게 확인할 수 있는 유용한 문서가 될 것입니다.


 

728x90
반응형
728x90
반응형

목차
1. API 명세서 설명
2. API 명세서 작성하기
3. 효율적인 API 명세서 작성 및 관리 방안

 


API(애플리케이션 프로그래밍 인터페이스) 명세서 설명

API명세서는 쉽게 말해 내가 만든 백엔드 서버의 사용 설명서입니다.

 

저는 팀 프로젝트이기 때문에 노션 에서 API명세서를 팀원들가 함께 작성했습니다

 

 

API명세서의 구성을 보면 왼쪽부터 해당기능의 담당자 / 진행상황 / HTTP메서드(get, post등) / 기능이름 / URL / 리퀘스트헤더 / 리스폰스헤더 / 리퀘스트 / 리스폰스 로 구성되어있습니다.

 

예를들어 워크스페이스 조회 기능같은 경우에는 로그인한 회원만 접근할 수 있는 기능 이기 때문에

해당 기능의 리퀘스트 헤드에는 토큰값을 필요로 한다는 의미에서 Authorization:Bearer 라고 명시를 했습니다

 


API명세서 작성하기

저희는 위 예시 사진과 같이 먼저 HTTP 메서드와 기능명들을 모두 작성한 후, 각 기능에 대한 세부 API 명세서를 작성하였습니다.

해당 기능들에 대해 어떤 리퀘스트 값을 받아야 하는지와 어떤 리스폰스를 반환할지를 명확히 정의하였습니다. 이를 통해 각 API의 입력과 출력을 구체적으로 규정하여, 개발자들이 구현 시 혼동 없이 작업할 수 있도록 하였습니다.

 

이번 프로젝트에서 필요한 기능들을 정리한 결과, 아래와 같은 표로 정리되었습니다.

로그인
회원가입
이메일 인증
사용자 정보 수정
회원탈퇴
워크스페이스 생성
워크 스페이스 조회
워크 스페이스 상세 조회
워크스페이스 멤버 초대
보드 조회
보드 상세 조회
보드 생성
보드 수정
보드 삭제
리스트 조회
리스트 상세 조회
리스트 생성
리스트 수정
리스트 삭제
리스트 순서 이동
카드 조회
카드 상세조회
카드 생성
카드 수정
카드 삭제
카드 이동
댓글 생성
댓글 수정
댓글 삭제
카드 마감일 관리
파일 첨부
파일 다운로드
체크리스트 생성
체크리스트 수정
체크리스트 삭제
아이템 생성
아이템 수정
아이템 삭제

 


효율적인 API 명세서 작성 및 관리 방안

 

전체 기능에 대한 API 명세서를 작성하였으나, 한 사람이 모든 명세서를 작성하기에는 양이 많아 비효율적이라 판단하여, 각 기능별로 담당자를 지정하고, 각자가 자신이 맡은 기능에 대한 API 명세서를 작성하도록 하였습니다.

 

API 명세서를 미리 작성하면, 요구사항이 명확해지고 개발 일관성이 유지됩니다. 프론트엔드와 백엔드가 동시에 작업할 수 있으며, 문서화와 테스트가 용이해집니다. 시스템 간 호환성 문제를 미리 파악하고, 초기 단계에서 문제를 발견할 수 있습니다. 또한, 팀 간 커뮤니케이션이 개선되고, 유지보수도 용이해집니다.

 

728x90
반응형
728x90
반응형

1. Nodemailer 설치하기

먼저 Nodemailer를 설치합니다.

npm install nodemailer

 

 


Nodemailer의 주요 구성 요소

  • Transporter: 실제로 이메일을 전송하는 우체부의 역할입니다. 이를 설정하면 "어떤 우체국 서버(Gmail, Outlook, 또는 다른 SMTP 서버)를 사용할지" 정해줍니다.
  • Mail Options: 발송할 편지의 내용입니다. 이메일 발신자, 수신자, 제목, 본문 등의 정보를 포함합니다.
  • sendMail() 메서드: 우체부가 우체국에 가서 편지를 보내는 동작에 해당합니다. sendMail() 메서드에 Mail Options를 전달하면 이메일이 발송됩니다.

NestJS에서 Nodemailer 사용 예제

이제 NestJS에서 Nodemailer를 통해 이메일을 보내는 방법을 알아보겠습니다. 이 과정에서는 Nodemailer를 MailService라는 서비스로 구현해 보겠습니다.

MailService 코드

인증번호가 포함된 이메일을 발송하기 위한 MailService를 작성합니다.

import { Injectable } from '@nestjs/common';
import * as nodemailer from 'nodemailer';

@Injectable()
export class MailService {
  private transporter: nodemailer.Transporter;

  constructor() {
    this.transporter = nodemailer.createTransport({
      service: 'Gmail',
      auth: {
        user: 'your-email@gmail.com',
        pass: 'your-email-password',
      },
    });
  }

  async sendVerificationCode(email: string, code: string) {
    const mailOptions = {
      from: 'your-email@gmail.com',
      to: email,
      subject: 'Your Verification Code',
      text: `Your verification code is: ${code}`,
    };

    await this.transporter.sendMail(mailOptions);
  }
}

 

2. AuthService 코드

AuthService는 인증번호 생성, 저장, 검증을 담당합니다. 간단한 메모리 객체에 인증번호를 저장해 보겠습니다. (실제 프로젝트에서는 Redis 같은 캐시 DB를 추천합니다.)

 

import { Injectable, BadRequestException } from '@nestjs/common';
import { MailService } from './mail.service';

@Injectable()
export class AuthService {
  private verificationCodes = new Map<string, string>(); // 이메일-인증번호 매핑 저장

  constructor(private readonly mailService: MailService) {}

  // 인증번호 생성 및 이메일 발송
  async sendVerificationCode(email: string) {
    const code = Math.floor(100000 + Math.random() * 900000).toString(); // 6자리 랜덤 코드 생성
    this.verificationCodes.set(email, code);

    await this.mailService.sendVerificationCode(email, code);
    return { message: 'Verification code sent to your email' };
  }

  // 인증번호 검증
  verifyCode(email: string, code: string) {
    const savedCode = this.verificationCodes.get(email);
    if (savedCode !== code) {
      throw new BadRequestException('Invalid verification code');
    }

    this.verificationCodes.delete(email); // 검증 후 코드 삭제
    return { message: 'Email verified successfully' };
  }
}

3. UserController 코드

UserController에서 회원가입 요청을 처리하고, 인증번호 발송 및 검증 로직을 구현합니다.

import { Controller, Post, Body } from '@nestjs/common';
import { AuthService } from './auth.service';

@Controller('auth')
export class UserController {
  constructor(private readonly authService: AuthService) {}

  @Post('register')
  async register(@Body('email') email: string) {
    return this.authService.sendVerificationCode(email);
  }

  @Post('verify')
  async verifyEmail(
    @Body('email') email: string,
    @Body('code') code: string
  ) {
    return this.authService.verifyCode(email, code);
  }

  @Post('complete-signup')
  async completeSignup(
    @Body('email') email: string,
    @Body('code') code: string,
    @Body('password') password: string
  ) {
    const verification = this.authService.verifyCode(email, code);
    if (verification.message === 'Email verified successfully') {
      // 여기에서 실제 사용자 저장 로직 실행 (DB에 저장 등)
      return { message: 'User signed up successfully' };
    }
  }
}

 

사용 흐름

  • /auth/register: 회원가입 요청을 받고 이메일로 인증번호 발송.
  • /auth/verify: 사용자가 입력한 인증번호가 서버에 저장된 인증번호와 일치하는지 검증.
  • /auth/complete-signup: 인증번호가 일치하면 비밀번호 등 추가 정보를 받아 회원가입 완료.

 

728x90
반응형
728x90
반응형
@nestjs/typeorm NestJS에서 TypeOrm을 사용하기 위해 연동시켜주는 모듈
typeorm TypeORM 모듈
pg Postgres 모듈

 

설치방법(npm패키지매니저 기준)

터미널에 npm install pg typeorm @nestjs/tyeorm --save 입력

 

nest.js에서 TypeORM을 사용해서 데이터베이스를 컨트롤 하는 방법이 나와있는 다큐멘테이션 주소입니다
참조하세요
https://docs.nestjs.com/techniques/database

 

Documentation | NestJS - A progressive Node.js framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Rea

docs.nestjs.com


 

728x90
반응형
728x90
반응형

로드밸런싱이란?

로드(Load)=서버가 받는 트레픽(또는 부하)를 잘 밸런싱해서

우리의 서버들한테 골고루 분산 시켜 주는 모듈을 로드 밸런서라고 부릅니다

 

트래픽이 늘어났을 때 선택할 수 있는 방법은 두 가지가 있습니다.

 

첫 번째는 Vertical Scale-Up(버티컬 스케일 업)입니다. 우리가 가지고 있는 서버 자체의 성능을 늘리는 방법입니다.

예를 들어, 서버의 램이 4기가였다면 32기가로 늘린다든지, 서버의 CPU를 업그레이드하는 방법입니다. 이 경우, 하나의 머신 성능을 올리는 것으로는 한계에 부딪힐 수밖에 없습니다.

 

두번째는 Horuzontal Scale-Out(수평적 확장) = 하나의 서버가 아닌 여러개의 서버로 분산시스템은 구축하는 방법입니다.

분산 시스템을 구축한다고 했을 때 중요해지는 개념이 바로 로드 밸런싱 입니다

트래픽을 각 서버로 잘 분산해주는 역할을 하는 것이 로드 밸런서이고, 이 행위를 우리는 로드 밸런싱이라고 부릅니다.


로드밸런싱 알고리즘

로드밸런싱에 대해 감을 잡았다면 이제 로드뱅런싱을 하기 위한 전략을 알아야 합니다.

 

Round Robin ( 라운드 로빈 )

첫번째로 가장 많이 사용되는 방법으로 라운드 로빈 알고리즘은
우리가 가지고있는 각 서버에 순차적으로 돌아가며 트레픽을 분배하는 방법으로

각 서버에 공평하게 요청을 배분하기 때문에 서버간 균형을 맞추기 쉽습니다.

 

Random Select ( 랜덤 셀렉트 )

말 그대로 우리가 가지고 있는 서버중에 아무 서버에 요청을 전달하는 방법입니다.

운이 안좋으면 한서버에 계속 트레픽이 몰릴수도 있지만 실제로 구현을 하면 라운드 로빈과 마찬가지로
꽤나 공평하게 트레픽이 서버에 전달 되는 결과를 볼수있기 때문에 좋을 알고리즘 중에 하나라고 볼 수 있을 것 같습니다.

 

지금부터는 조금 복잡할 수 있지만 조금더 스마트한 알고리즘을 알아보겠습니다.

 

Least Connection ( 리스트 커넥션 )

리스트 커넥션 알고리즘은 서버가 로드 밸런서에게 얼마나 많은 트래픽을 처리하고 있는지를 알려줍니다. 이를 통해 로드 밸런서는 가장 적게 일하는 서버로 트래픽을 전달합니다.

서버의 부하 상태를 실시간으로 모니터링하여 트래픽을 조절하기 때문에, 비동기 요청이나 긴 연결을 많이 사용하는 애플리케이션에서 유리합니다.

또한, 여러 서버 중에서 성능이 좋은 서버는 트래픽을 빠르게 처리하고, 성능이 좋지 않은 서버는 트래픽 처리 속도가 느리기 때문에, 성능이 좋은 서버에 더 많은 트래픽을 할당하여 효율성을 높일 수 있습니다.


로드밸런싱 헬스체크

로드밸런싱에서 헬스체크(Health Check)는 로드 밸런서가 서버의 상태를 주기적으로 확인하여, 장애가 발생한 서버로의 트래픽을 자동으로 차단하고 정상적인 서버로만 요청을 분배할 수 있도록 하는 중요한 기능입니다.

 

헬스체크는 다양한 방법으로 수행될 수 있으며, 다음은 주요 헬스체크 방식들입니다.

 

  • Ping 헬스체크: ICMP 프로토콜의 Ping 패킷으로 서버의 네트워크 연결 상태를 확인합니다.
  • TCP 헬스체크: 특정 포트로 TCP 연결을 시도하여 해당 포트가 열려 있는지 확인합니다.
  • HTTP/HTTPS 헬스체크: 특정 HTTP/HTTPS 엔드포인트에 요청을 보내고 응답 상태 코드로 서버의 상태를 판단합니다.
  • UDP 헬스체크: UDP 프로토콜로 메시지를 보내고 응답 여부를 확인합니다.
  • 애플리케이션 레벨 헬스체크: 서버 내부의 리소스 상태나 애플리케이션 의존성을 모니터링합니다.

 

 

 

728x90
반응형
728x90
반응형

 

728x90
반응형
728x90
반응형

쓸모있어보이는것만 추린

전체는https://www.typescriptlang.org/tsconfig 에서 구경가능

 

{
 "compilerOptions": {

  "target": "es5", // 'es3', 'es5', 'es2015', 'es2016', 'es2017','es2018', 'esnext' 가능
  "module": "commonjs", //무슨 import 문법 쓸건지 'commonjs', 'amd', 'es2015', 'esnext'
  "allowJs": true, // js 파일들 ts에서 import해서 쓸 수 있는지 
  "checkJs": true, // 일반 js 파일에서도 에러체크 여부 
  "jsx": "preserve", // tsx 파일을 jsx로 어떻게 컴파일할 것인지 'preserve', 'react-native', 'react'
  "declaration": true, //컴파일시 .d.ts 파일도 자동으로 함께생성 (현재쓰는 모든 타입이 정의된 파일)
  "outFile": "./", //모든 ts파일을 js파일 하나로 컴파일해줌 (module이 none, amd, system일 때만 가능)
  "outDir": "./", //js파일 아웃풋 경로바꾸기
  "rootDir": "./", //루트경로 바꾸기 (js 파일 아웃풋 경로에 영향줌)
  "removeComments": true, //컴파일시 주석제거 

  "strict": true, //strict 관련, noimplicit 어쩌구 관련 모드 전부 켜기
  "noImplicitAny": true, //any타입 금지 여부
  "strictNullChecks": true, //null, undefined 타입에 이상한 짓 할시 에러내기 
  "strictFunctionTypes": true, //함수파라미터 타입체크 강하게 
  "strictPropertyInitialization": true, //class constructor 작성시 타입체크 강하게
  "noImplicitThis": true, //this 키워드가 any 타입일 경우 에러내기
  "alwaysStrict": true, //자바스크립트 "use strict" 모드 켜기

  "noUnusedLocals": true, //쓰지않는 지역변수 있으면 에러내기
  "noUnusedParameters": true, //쓰지않는 파라미터 있으면 에러내기
  "noImplicitReturns": true, //함수에서 return 빼먹으면 에러내기 
  "noFallthroughCasesInSwitch": true, //switch문 이상하면 에러내기 
 }
}
728x90
반응형
728x90
반응형

KEEP

- 지금처럼 활발하게 소통하기
- 질문 있으면 바로바로 하기

Problem

- 시간 관리 실패
- 테스트 코드를 너무 미뤘다가 작성
- 커밋을 너무 한번에 몰아서 함

Try

- 우선순위 선정 필요
- 테스트코드를 기능개발에 맞춰서 작성하기
- 기능 개발 단계 마다 커밋하기

Problem 항목에 대해서 좀 더 개인적인 회고를 하자면
프로젝트 발표날 추가로 트랜잭션에 대한 발표를 할 수 있는 기회를 우리 조를 담당해주시는 튜터님께서 준비해주셔서

우리가 이제 100여명의 앞에서 조사한 트랜잭션에 대해서 발표해야했는데 이게 프로젝트 완성에 너무 힘을 줘서
트랜잭션 발표 준비를 각자 5명이 각각 조사만 하고 하나로 모은 결과물이 없었다 그래서 발표는 결국 없던 일이 됐는데
아 이게 개인적으로 정말 아쉬웠다 튜터님 말대로 하루 1시간만 투자했으면 충분히 결과물이 나와서
튜터님 피드백 받아서 추가할 부분 추가하고 잘못된 부분 수정하는 과정을 거쳐서 발표를 진행 했을텐데...

그래서 약간 시간 관리의 중요성을 다시금 체감했고

또 프로젝트 발표 PPT를 작성 중 아 뭔가 이 프로젝트를 만들면서 힘들었던 부분이 굉장히 많았고 굉장히 무릎을 치게 만든(내 기준) 해결법도 있었는데
이걸 전부 기록하지 않아서 기억 나는게 별로 없어서 트러블 슈팅 부분을 작성하는데 굉장히 애를 먹었다.
그래서 이제 내일(17일)부터 TS, NEST 공부를 시작하고 온라인 예매 서비스 과제에 들어가는데
이때는 진짜로 매일매일 TIL을 기록하면서 작업 진행을 기록해야겠다

기록의 중요성을 느꼈다.

728x90
반응형
728x90
반응형

1. VS코드 라이브쉐어란?

VS코드 라이브쉐어(Live Share)는 마이크로소프트의 Visual Studio Code에서 제공하는 확장 기능으로, 개발자들이 실시간으로 코드를 공유하고 협업할 수 있도록 돕는 도구입니다. 여러 개발자가 동시에 동일한 프로젝트에서 작업할 수 있으며, 원격지에 있는 팀원들과의 협업을 쉽게 만들어줍니다.


2. 라이브쉐어의 장점

  • 실시간 협업: 팀원들이 동시에 코드를 수정하고, 변경 사항을 실시간으로 확인할 수 있습니다.
  • 디버깅 공유: 공동 디버깅 세션을 통해 팀원들과 함께 문제를 해결할 수 있습니다.
  • 간편한 설치 및 사용: 별도의 복잡한 설정 없이 손쉽게 사용할 수 있습니다.
  • 플랫폼 무관: Windows, macOS, Linux 등 다양한 운영 체제에서 사용할 수 있어 호환성이 뛰어납니다.
  • 채팅 및 음성 통화: 내장된 채팅 기능과 음성 통화를 통해 커뮤니케이션이 원활합니다.

3. 라이브쉐어의 단점

  • 인터넷 의존성: 안정적인 인터넷 연결이 필요하며, 연결이 불안정할 경우 협업에 차질이 생길 수 있습니다.
  • 보안 문제: 공유 세션 중 외부 사용자가 접근할 수 있어 보안에 유의해야 합니다.
  • 성능 저하: 대용량 프로젝트에서 사용 시, 성능이 저하될 수 있습니다.

4. 라이브쉐어 설치 방법

  1. 라이브쉐어 확장 설치
    • 1-1. VS코드를 열고 왼쪽 사이드바의 'Extensions' 아이콘을 클릭합니다.
    • 1-2. 검색창에 'Live Share'를 입력하고, 'Live Share'를 설치합니다.

5. 라이브쉐어 사용법

  1. 세션 시작(내프로젝트에서 협업하기)
    • 좌측 하단의 'Live Share' 아이콘을 클릭합니다.
    • Share (Read/Write)Share (Read-Only)중 하나를 선택합니다
      • Share (Read/Write) : 모든 참가자가 파일을 추가, 삭제, 수정할 수 있습니다.
      • Share (Read-Only) : 참가자는 코드를 확인할 수 있지만, 파일을 수정하거나 삭제할 수 없습니다.
  2. 세션 공유:
    • Share (Read/Write)Share (Read-Only)중 하나를 선택하면 링크가 생성되며 자동으로 복사됩니다.
    • 생성된 링크를 팀원들과 공유합니다. 팀원들은 링크를 클릭하여 세션에 참여할 수 있습니다.
    • Ctrl + V 키로 링크 공유가능
  3. 협업 진행:
    • 팀원들과 동시에 코드를 수정하고, 디버깅 세션을 진행합니다.
    • 채팅 기능이나 음성 통화를 통해 실시간으로 소통합니다.
728x90
반응형
728x90
반응형

트랜잭션 격리 수준의 종류


레벨1 : READ UNCOMMITTED (커밋되지 않은 읽기)

  • 설명: 트랜잭션이 커밋되지 않은 변경 사항을 읽을 수 있습니다.
    • 사용자 A가 계좌에 1000원을 입금하고, 아직 커밋하지 않은 상태에서 사용자 B가 그 계좌의 잔액을 조회합니다. 사용자 B는 A의 입금이 반영된 1000원이 추가된 잔액을 보게 되지만, A가 트랜잭션을 롤백하면 B의 정보는 잘못된 것이 됩니다.
  • 장점: 성능이 가장 좋음
  • 단점: 데이터 무결성 보장이 어렵습니다.

레벨2 : READ COMMITTED (커밋 읽기)

  • 설명: 트랜잭션은 커밋된 데이터만 읽을 수 있습니다.
  • 예시:
    • 사용자 A가 1000원을 입금한 후, 이를 커밋합니다. 그 후 사용자 B가 잔액을 조회하면, B는 1000원이 추가된 올바른 잔액을 볼 수 있습니다. 그러나 B가 같은 쿼리를 두 번 실행할 경우, A가 중간에 다른 금액을 입금하면 B는 두 번의 쿼리 결과가 다를 수 있습니다(비 반복 읽기).
  • 장점: 데이터의 일관성이 어느 정도 유지됨
  • 단점: 트랜잭션 간의 충돌이 발생할 수 있음

레벨 3 : REPEATABLE READ (반복 가능한 읽기)

  • 설명: 트랜잭션 내에서 동일한 쿼리를 실행할 때 항상 같은 결과를 반환합니다.
  • 예시:
    • 사용자 A가 1000원을 입금한 후 커밋합니다. 사용자 B가 잔액을 조회하고, B가 그 결과를 기반으로 다른 트랜잭션을 시작합니다. 이 때 A가 중간에 다른 금액을 입금해도, B는 첫 번째 쿼리 실행 시의 잔액을 계속 볼 수 있습니다. 그러나 B가 새로 추가된 잔액이 반영된 결과를 쿼리하려 할 때, A가 추가한 항목 때문에 팬텀 읽기가 발생할 수 있습니다.
  • 장점: 데이터의 일관성이 높음
  • 단점: 성능 저하가 발생할 수 있음

레벨 4 : SERIALIZABLE (직렬화 가능)

  • 설명: 가장 높은 수준의 격리로, 트랜잭션이 직렬로 실행되는 것처럼 보이게 합니다.
  • 예시:
    • 사용자 A가 1000원을 입금하고, 사용자 B가 동시에 잔액을 조회하려 할 때, B는 A의 트랜잭션이 완료될 때까지 기다려야 합니다. 이렇게 함으로써 A가 커밋한 후에만 B가 잔액을 조회하게 되므로 모든 읽기 작업이 일관되게 진행됩니다. 하지만 이러한 대기 상태로 인해 성능은 저하됩니다.
  • 장점: 데이터 무결성이 가장 보장됨
  • 단점: 성능이 크게 저하될 수 있음

위의 각 트랙잭션 격리수준의 특징과 장단점을 고려해서 성능과 데이터 무결성 간의 균형을 격리수준을 선택합니다.

 

주문 동시 처리에서 발생할 수 있는 문제

  1. 재고 충돌 (Stock Conflict)
    • 여러 사용자가 동시에 같은 상품을 주문할 경우, 재고 수량이 줄어들면서 재고가 부족해질 수 있습니다. 예를 들어, A와 B가 동시에 1개씩 주문하는 경우, 재고가 1개뿐이라면 두 주문 중 하나만 처리될 수 있습니다.
  2. 더러운 읽기 (Dirty Read)
    • 한 트랜잭션이 다른 트랜잭션의 커밋되지 않은 변경 사항을 읽는 경우입니다. 예를 들어, 주문 처리 중에 다른 사용자가 주문을 변경하고 이를 조회한 경우, 올바르지 않은 정보를 기반으로 결정을 내릴 수 있습니다.
  3. 비 반복 읽기 (Non-Repeatable Read)
    • 트랜잭션이 실행되는 동안 같은 쿼리를 여러 번 실행했을 때 결과가 다르게 나타나는 문제입니다. 예를 들어, A가 주문을 생성하고, B가 중간에 그 주문을 변경하면 A는 그 변경된 결과를 반영한 정보를 보게 됩니다.
  4. 팬텀 읽기 (Phantom Read)
    • 트랜잭션이 실행되는 동안 새로운 데이터가 삽입되는 경우 발생합니다. 예를 들어, A가 특정 조건에 맞는 상품 목록을 조회하는 동안 B가 새로운 상품을 추가하면, A는 B가 추가한 상품을 볼 수 있습니다.

해결 방법

  1. 격리 수준 조정
    • 트랜잭션의 격리 수준을 높여서 동시성 문제를 줄일 수 있습니다. 예를 들어, SERIALIZABLE 격리 수준을 사용하면 모든 트랜잭션이 직렬로 처리되므로 충돌을 방지할 수 있습니다. 그러나 성능이 저하될 수 있다는 점을 고려해야 합니다.
  2. 낙관적 및 비관적 잠금
    • 낙관적 잠금: 트랜잭션이 완료될 때까지 변경 사항을 확인하고, 충돌이 발생할 경우 롤백합니다. 주로 데이터 충돌이 드물 때 유용합니다.
    • 비관적 잠금: 트랜잭션이 시작될 때 데이터에 잠금을 걸어 다른 트랜잭션이 접근하지 못하도록 합니다. 일반적으로 동시성이 높을 때 사용됩니다.
  3. 재고 체크 및 주문 처리 로직
    • 주문을 처리하기 전에 재고를 확인하고, 재고가 충분한 경우에만 주문을 진행하도록 로직을 구현합니다. 이때, 재고 수량을 업데이트하는 트랜잭션을 안전하게 처리하는 것이 중요합니다.
  4. 큐 기반 처리
    • 주문 요청을 큐에 쌓아 순차적으로 처리하는 방법입니다. 이렇게 하면 동시에 들어온 주문을 순차적으로 처리할 수 있어 충돌을 줄일 수 있습니다.
  5. 원자적 처리 (Atomic Processing)
    • 트랜잭션을 원자적으로 처리하여 모든 단계가 성공하거나 실패하도록 합니다. 이 방법은 데이터의 일관성을 높이고, 중간 상태에서 발생할 수 있는 문제를 방지합니다.
728x90
반응형
728x90
반응형

프레젠테이션 계층(컨트롤러)

아키텍쳐 패턴의 3계층 중에서 프레젠테이션 계층에 속하는 컨트롤러는
클라이언트의 요청을 가장먼저 만나는 계층입니다.
  • 컨트롤러의 역활
클라이언트 요청 수신 요청 속 데이터 검증 최종 결과 반환(Response)

클라이언트의 요청을 받은 후 요청 속 사용자 입력 검증등을 한 후 다음 계층으로 보냅니다.

하위 계층에서 최종 결과를 받아서 클라이언트에게 결과반환(Response)의 역활을 합니다.

그리고 전역 오류 처리등의 예외 처리를 담당함으로서 에러처리 미들웨어를 사용하는 곳입니다.

게시글 작성 컨트롤러가로 가정했을 경우

src/controllers 경로에 posts.controller.js <<파일을 만들고

예시 사진 처럼 api를 작성하며 트라이 케치, 에러처리 미들웨어 등을 사용하며 요청을 처리하는 비즈니스 로직은

이곳에 적성하지 않고 단순히 요청을 받아서 검증하고 로직을 수행하는 다른 계층으로 요청을 넘기는 역활만을 수행합니다. 


서비스 계층 (비즈니스 계층이라고도 부름)

핵심적인 비즈니스로직을 수행하는 계층으로 위의 프레젠테이션 계층에서 요청을 전달받아서
실제로 그 요청을 수행라는 로직을 구현하는 계층입니다.
  • 데이터를 파싱하거나 정렬하는 등의 핵심적인 "기능"을 구현

게시글 관련 기능을 하는 기능을 만든다는 예시를 들었을 경우

src/services 경로에 posts.service.js등으로 파일을 만들고 비즈니스 로직을 작성

게시글 조회 요청이 들어왔을 경우 위 예시사진처럼 조회결과를 정렬하거나

특정 데이터를 제외한 결과를 반환하는 작업을 수행하는등 필요한 핵심기능들을 수행하는 역활을 합니다


저장소 계층(Data Access Layer)

데이터베이스와 관련된 작업만을 처리하는 계층으로
데이터를 생성,조회,수정,삭제등의 CRUD기능을 구현하는곳 입니다.

저장소계층(데이터 엑세스 계층)을 사용할 경우

  • 데이터의 저장방법을 더욱 쉽게 변경 가능
  • 테스트코드 작성시 가짜저장소를 제공하기 쉬움
    • 유닛 단위로 코드를 테스트 할 때 저장소 계층만 제외시키면 되기때문

저장소 계층에서 로우쿼리를 사용하던 파인드올을 사용하던간에 경과만 정상으로 도출되면

다른 코드들에게 영향을 주지 않음

728x90
반응형
728x90
반응형

728x90
반응형
728x90
반응형

게임 개발은 어떤 단계로 이뤄질까

 

첫번째 : 기획 단계

기획단계에서는 PD, TD, AD라는 세사람이 등장합니다.

PD( Project Director  )
한 팀의 헤드 역활을 하며 게임 전반의 방향성을 결정
방송의 PD와 비슷한 역활
시나리오, 장르, 방향성 → 문서로 만들어줌

 

AD( Art Director )
아트팀의 모든 방향성을 결정
3D 그래픽, 2D 컨셉 등 가능성 여부 결정
PD의 문서를 보고 컨셉아트를 그려줌

 

TD( Technical Director )
서버팀, 클라이언트팀 등 모든 기술팀의 헤드 역활
전체적인 기술의 흐름 및 방향성을 결정
{회사 마다 명칭이 다른 경우가 있음 TL등등
모든 자료를 토대로 프로토타입의 게임을 만듬
기획 단계에서 만든 프로토타입의 게임은 서버가 거창하게
있거나 그렇지 않고 클라이언트 위주로 만

두번째 : 개발 단계( 서버 개발자 기준 )

사실 서버팀은 개발 단계에서 그렇게까지 바쁘지 않다.

 

게임의 장르에 따라서 팀의 규모가 정해지는데 "팀", "셀", "스튜디오" 등 회사마다 팀을 부르는 호칭이 달라질 수 있음

 

이 시기에 서버팀이 하는 일은?

  • 인프라 구성
    • 대규모 트래픽처리를 위한 분산 서버 구성( 테스트 정도 수준)
    • 업데이트 방식 설계 → 서버를 다내렸다 키는방식을 할꺼냐, 아니면 롤링방식으로 업데이트를 할꺼냐 등을 정함
    • 서버 관리, 모니터링 툴 적용
    • NAS, 내부망, 클라우드 세팅
  • 팀원 모집
    • 인프라, 클라우드, DBA, 웹, 게임서버
  • 서버 로직 개발
    • 오픈 컨텐츠 개발 대응
    • 더미테스트, 부화테스트 진행
    • 내, 외부 QA 대

세번째 : 라이브 단계( 오픈단계 )

서비스 릴리즈 날짜가 정해졌다면 사무실 불은 끄지 마라

즉 라이브 단계부터 바빠짐

 

오픈 이후에는 ?

  • 처음 몇달간 이슈대응으로 고생하면 또 다시 점점 할 일이 적어짐(상대적으로)
  • 트래픽의 경우는 점진적으로 감소하는것이 일반적이라 크게 대응할 일이 없어짐
    • 업데이트의 경우에만 바짝 긴장
  • 게임 컨텐츠 개발의 연속X100
    • 미션추가, 전투 형태 변경, pvp등
  • 각종 이벤트 대응
    • 외부 투자사, 콜라보를 통해 진행하는 이벤트 로직 개발 및 기존 코드에 적용

728x90
반응형
728x90
반응형

풋살 온라인 팀프로젝트 회고록

KEEP (잘된 점)

팀원 간 활발한 소통: 팀원들이 서로 적극적으로 소통하며 프로젝트를 원활하게 진행함.

모르는게 있을시 서로 질문할수 있었음
능동적인 프로젝트 진행: 각자가 부족한 부분을 보완하며 능동적으로 프로젝트에 참여하고 책임감 있게 진행함.

PROBLEM (문제점)

스키마 설계의 어려움: 데이터베이스 스키마 설계에 혼란이 있어 개발 진행에 차질이 발생함.
기록 부족: 팀 노션에 중요한 정보와 진행 상황을 충분히 기록하지 않아 정보 공유에 어려움이 있었음.
회의록 미작성: 회의 후 논의된 내용을 기록하지 않아 나중에 회의 내용을 참고하거나 피드백하는 데 어려움이 발생함.
시간 부족: 연휴로 인해 구현에 필요한 충분한 시간을 확보하지 못함.
코드리뷰 부족: 서로 간의 코드 리뷰를 자주 진행하지 못함.

TRY (시도할 점)

스키마 설계에 시간 투자: 스키마 설계에 충분한 시간을 들여 꼼꼼하게 진행하여 이후 개발 과정에서 문제를 줄이기.
기록의 적시성: 중요한 사항과 진행 상황을 제때 기록하고, 팀 노션을 활용해 정보 공유 강화.
회의록 작성 및 공유: 회의 후 각자 회의록을 작성하여 이를 합쳐 공식 회의록으로 공유, 소통 명확화.

초기부터 DB설계를 디테일하게 하고 효율성과 관계를 많이 고려해야함

728x90
반응형
728x90
반응형

1xx: 정보 응답

  • 100 Continue: 요청을 계속 진행해도 좋음을 나타냅니다.
  • 101 Switching Protocols: 프로토콜 변경을 요청한 클라이언트의 요구를 서버가 수락했음을 나타냅니다.

2xx: 성공

  • 200 OK: 요청이 성공적으로 처리되었음을 나타냅니다. 가장 많이 사용하는 상태 코드 중 하나입니다.
  • 201 Created: 요청이 성공적으로 처리되었으며, 새로운 리소스가 생성되었음을 나타냅니다.
  • 204 No Content: 요청이 성공적이지만 반환할 콘텐츠가 없음을 나타냅니다.

3xx: 리다이렉션

  • 301 Moved Permanently: 요청한 리소스의 URL이 영구적으로 변경되었음을 나타냅니다. 브라우저나 클라이언트는 새로운 URL로 리다이렉트됩니다.
  • 302 Found: 요청한 리소스가 임시적으로 다른 URL에 있습니다. 클라이언트는 리다이렉트할 수 있지만, URL 변경은 영구적이지 않습니다.
  • 304 Not Modified: 클라이언트가 이전에 요청한 데이터가 변경되지 않았음을 나타냅니다. 캐시된 데이터를 사용하도록 권장합니다.

4xx: 클라이언트 오류

  • 400 Bad Request: 클라이언트의 요청이 잘못되었음을 나타냅니다. 잘못된 형식이거나 요청 데이터가 유효하지 않을 때 발생합니다.
  • 401 Unauthorized: 인증이 필요하거나, 인증 정보가 유효하지 않을 때 발생합니다.
  • 403 Forbidden: 서버가 요청을 이해했으나, 권한이 없어 요청을 거부합니다.
  • 404 Not Found: 요청한 리소스를 찾을 수 없음을 나타냅니다. 가장 많이 발생하는 에러 중 하나입니다.
  • 405 Method Not Allowed: 요청한 HTTP 메서드가 허용되지 않음을 나타냅니다.
  • 429 Too Many Requests: 클라이언트가 너무 많은 요청을 보내서 서버가 더 이상 요청을 처리할 수 없음을 나타냅니다. 일반적으로 API에서 사용합니다.

5xx: 서버 오류

  • 500 Internal Server Error: 서버에서 요청을 처리하는 도중 예기치 않은 오류가 발생했음을 나타냅니다.
  • 502 Bad Gateway: 서버가 게이트웨이로부터 잘못된 응답을 받았음을 나타냅니다.
  • 503 Service Unavailable: 서버가 현재 요청을 처리할 수 없음을 나타냅니다. 주로 서버 과부하나 유지보수 중일 때 발생합니다.
  • 504 Gateway Timeout: 게이트웨이 또는 프록시 서버가 지정된 시간 내에 응답을 받지 못했음을 나타냅니다.

이 상태 코드들은 API 개발, 웹 애플리케이션 처리 등에서 자주 사용되며, 올바르게 활용하면 사용자에게 보다 명확한 정보 전달과 디버깅이 가능합니다.

728x90
반응형
728x90
반응형

프리즈마란?

프리즈마(Prisma)는 데이터베이스와 쉽게 소통할 수 있게 도와주는 ORM 도구입니다.

주로 Node.js 및 TypeScript 환경에서 사용되며

보통 데이터베이스에 정보를 저장하거나 가져오려면 복잡한 SQL 쿼리문을 써야 하는데,

프리즈마를 사용하면 코드만으로 이런 작업들을 간단하게 할 수 있습니다.


프리즈마의 핵심 개념

ORM

 ㄴ ORM은 데이터베이스의 테이블을 코드에서 객체로 다룰 수 있게 해주는 기술입니다. 프리즈마는 ORM 도구로,

      SQL 없이 데이터베이스의 데이터를 쉽게 가져오거나 수정할 수 있게 도와줍니다.

프리즈마 스키마

 ㄴ 프리즈마를 사용하려면 먼저 데이터 구조(스키마)를 정의해야 합니다.

      이 스키마 파일에서 어떤 테이블이 있고, 테이블에 어떤 정보가 저장될지 미리 설정합니다.

      예를 들어, User라는 테이블이 있고 그 안에 id, email, name 같은 필드가 있다고 설정합니다.

//프리즈마 스카마 예시
model User {
  id    Int     @id @default(autoincrement()) // 기본 키, 자동 증가하는 정수 값
  email String  @unique                      // 고유한 이메일 필드
  name  String?                              // 선택적인 이름 필드 (null 가능)
}

 

프리즈마 클라이언트

 ㄴ 스키마가 정의되면, 프리즈마는 자동으로 코드를 생성해 줍니다.

      이 코드를 통해 데이터베이스와 쉽게 소통할 수 있는데, 이것이 바로 프리즈마 클라이언트입니다.

      클라이언트를 사용하면 SQL을 쓰지 않고도 데이터를 쉽게 저장하고 불러올 수 있습니다.


사용법

프로젝트에 프리즈마를 설치합니다. 코드 에디터의 터미널에

// 코드에디터 터미널에

npm init <- 엔피엠 인잇 입력 후

// package.json 파일의 생성이 확인된다면 

npm install prisma @prisma/client

를 입력합니다

 

 

 

728x90
반응형
728x90
반응형

미들웨어가 뭐고 왜써야하는지 알려줌

 

미들웨어는 서버만들때 요청이 들어오면 응답을 해주는 API를 만들때

요청을 받고 응답을 해주기전에 여러가지 기능을 수행할 수 있게 해주는거임

이게뭔말이냐면

 

예를들어 클라이언트로부터 게시물을 보는 gat요청이 들어오면

해당 게시물을 응답해줘야할꺼 아닙니까

근데 로그인을 한사람만 게시물을 볼수있게 하고싶으면 어쩝니까?

API코드 작성할때 로그인을 했는지 검사하는 코드를 작성하면 되는데

로그인이 필요한 수많은 API들에 로그인 검사코드를 하나하나 작성하면 너무 비효울 적일꺼같습니다

 

그럴때 미들웨어를 사용하면 손쉽게 로그인이 되어있는지 확인한 뒤에 게시물을 응답해주는 API를 만들수 있습니다

 

//로그인 검사하는 함수를 대충만듬

function 로그인검사(요청, 응답){
	if(!요청.user){ //로그인정보가 없으면
    	응답.send("로그인하세요~") //로그인하세요를 응답해줌
    }
}
              ▼여기에 함수명 써서 이게 실행된후 다음 으로 넘어감 여기를 '미들웨어'라고 부름
app.get('/', 로그인검사, (요청, 응답, next)=>{
	//메인페이즈 보여주는 코드~~
})

 


근데 이것도 로그인이 필요한 모든 API에 넣기 힘들지 않겠습니까

API 1000개 있으면 매운 곤란할꺼 같습니다

그럴때 사용할 수 있는 방법이

//로그인 검사하는 함수를 대충만듬

function 로그인검사(요청, 응답){
	if(!요청.user){ //로그인정보가 없으면
    	응답.send("로그인하세요~") //로그인하세요를 응답해줌
    }
}

app.use(로그인검사) <--'이 코드 아래에 있는거 모두 미들웨어 자동적용됨'

app.get('/', (요청, 응답, next)=>{
	//메인페이즈 보여주는 코드~~
})

근데 아래있는거 모두는 말고 특정 URL만 로그인검사를 하고싶으면 어쩝니까

그럴때

//로그인 검사하는 함수를 대충만듬

function 로그인검사(요청, 응답){
	if(!요청.user){ //로그인정보가 없으면
    	응답.send("로그인하세요~") //로그인하세요를 응답해줌
    }
}

app.use('/어쩌구', 로그인검사); <-'/어쩌구 로 시작하는 모든API에 미들웨어 자동적용~'

app.get('/', 로그인검사, (요청, 응답, next)=>{
	//메인페이즈 보여주는 코드~~
})

app.get('/어쩌구', 로그인검사, (요청, 응답, next)=>{
	//메인페이즈 보여주는 코드~~
})

미들웨어를 잘 활용하면 요청이 왔을때 현재 시간을 출력한다던지 상상력을 더해서 유용하게 사용할수 있습니다

728x90
반응형
728x90
반응형

JavaScript  문자열의 내용 변경, 검색, 분할, 조합 등의 작업을 수행하는 데 유용한 메서드 모음

즐코하세요~


문자열 검색탐색 메서드

indexOf(검색어, 시작 위치): 문자열에서 특정 문자열을 찾아서 처음 등장하는 위치(인덱스)를 반환합니다. 찾지 못하면 -1을 반환합니다.

let str = "Hello, world!";
console.log(str.indexOf("world")); // 출력: 7
console.log(str.indexOf("world", 8)); // 출력: -1 (8번째 인덱스 이후에 "world"가 없음)

 

lastIndexOf(검색어, 시작 위치): 문자열에서 특정 문자열을 찾아서 마지막으로 등장하는 위치를 반환합니다. 찾지 못하면 -1을 반환합니다.

let str = "Hello, world! Hello again!";
console.log(str.lastIndexOf("Hello")); // 출력: 13

 

includes(검색어, 시작 위치): 문자열에 특정 문자열이 포함되어 있는지를 true 또는 false로 반환합니다.

let str = "Hello, world!";
console.log(str.includes("world")); // 출력: true

 

startsWith(검색어, 시작 위치): 문자열이 특정 문자열로 시작하는지를 true 또는 false로 반환합니다.

let str = "Hello, world!";
console.log(str.startsWith("Hello")); // 출력: true

 

endsWith(검색어, 길이): 문자열이 특정 문자열로 끝나는지를 true 또는 false로 반환합니다.

let str = "Hello, world!";
console.log(str.endsWith("world!")); // 출력: true

 


문자열 변형 메서드

toUpperCase(): 문자열을 모두 대문자로 변환합니다.

let str = "Hello, world!";
console.log(str.toUpperCase()); // 출력: "HELLO, WORLD!"

 

toLowerCase(): 문자열을 모두 소문자로 변환합니다.

let str = "Hello, world!";
console.log(str.toLowerCase()); // 출력: "hello, world!"

 

trim(): 문자열의 앞뒤 공백을 제거합니다.

let str = "   Hello, world!   ";
console.log(str.trim()); // 출력: "Hello, world!"

 

trimStart(): 문자열의 앞쪽 공백을 제거합니다.

let str = "   Hello, world!";
console.log(str.trimStart()); // 출력: "Hello, world!"

 

trimEnd(): 문자열의 뒤쪽 공백을 제거합니다.

let str = "Hello, world!   ";
console.log(str.trimEnd()); // 출력: "Hello, world!"

 

repeat(횟수): 문자열을 주어진 횟수만큼 반복하여 결합한 새 문자열을 반환합니다.

let str = "Hello!";
console.log(str.repeat(3)); // 출력: "Hello!Hello!Hello!"

 

replace(검색어 또는 정규식, 대체 문자열): 문자열에서 특정 부분을 다른 문자열로 대체합니다.

let str = "Hello, world!";
console.log(str.replace("world", "JavaScript")); // 출력: "Hello, JavaScript!"

 


문자열 분할 메서드

split(구분자, 제한): 문자열을 구분자를 기준으로 나누어 배열로 반환합니다

let str = "apple, banana, cherry";
let arr = str.split(", ");
console.log(arr); // 출력: ["apple", "banana", "cherry"]

 


문자열 결합 메서드

concat(문자열1, 문자열2, ...): 두 개 이상의 문자열을 하나로 결합합니다. 여러 문자열을 합칠 때 사용됩니다.

let str1 = "Hello";
let str2 = "world";
let result = str1.concat(", ", str2, "!");
console.log(result); // 출력: "Hello, world!"

 


문자열 추출 메서드

slice(시작 인덱스, 끝 인덱스): 문자열의 일부를 추출하여 새 문자열을 반환합니다. 끝 인덱스는 포함되지 않습니다.

let str = "Hello, world!";
console.log(str.slice(7, 12)); // 출력: "world"

 

substring(시작 인덱스, 끝 인덱스): slice()와 유사하게 동작하며, 음수 인덱스를 허용하지 않습니다.

let str = "Hello, world!";
console.log(str.substring(7, 12)); // 출력: "world"

 

substr(시작 인덱스, 길이): 지정된 위치에서 시작해 특정 길이만큼의 문자열을 반환합니다. (이 메서드는 더 이상 권장되지 않음)

let str = "Hello, world!";
console.log(str.substr(7, 5)); // 출력: "world"

 


문자열의 길이 메서드

length: 문자열의 길이를 반환합니다

let str = "Hello, world!";
console.log(str.length); // 출력: 13

 


문자열 비교 메서드

localeCompare(다른 문자열): 문자열을 비교하여 정렬 순서를 결정합니다. 이 메서드는 문자열 간의 비교 결과를 -1, 0, 1로 반환하여 사전식 정렬 등에 사용됩니다.

let str1 = "apple";
let str2 = "banana";
console.log(str1.localeCompare(str2)); // 출력: -1 (str1이 str2보다 앞에 위치)

문자 인덱스로 접근

charAt(인덱스): 주어진 인덱스에 위치한 문자를 반환합니다.

let str = "Hello";
console.log(str.charAt(1)); // 출력: "e"

 

charCodeAt(인덱스): 주어진 인덱스에 위치한 문자의 UTF-16 코드를 반환합니다.

let str = "Hello";
console.log(str.charCodeAt(1)); // 출력: 101 ("e"의 UTF-16 코드)

 


정규 표현식 사용 메서드

match(정규식): 문자열이 정규식과 매칭되는 부분을 배열로 반환합니다.

let str = "Hello, world!";
console.log(str.match(/o/g)); // 출력: ["o", "o"] (모든 "o"를 배열로 반환)

 

search(정규식): 문자열이 정규식과 매칭되는 첫 번째 위치를 반환합니다.

let str = "Hello, world!";
console.log(str.search(/world/)); // 출력: 7 ("world"가 시작되는 위치)

 

replace(정규식, 대체 문자열): 정규식에 매칭되는 부분을 대체 문자열로 바꿉니다.

let str = "Hello, world!";
console.log(str.replace(/world/, "JavaScript")); // 출력: "Hello, JavaScript!"

 

split(정규식): 정규식을 사용해 문자열을 나누고, 결과를 배열로 반환합니다.

let str = "one, two, three";
let arr = str.split(/\s*,\s*/); // 쉼표와 공백을 기준으로 나눔
console.log(arr); // 출력: ["one", "two", "three"]

 


이상입니다. 북마크 해놓으셨다가 필요할 때

적당한거 있는지 둘러볼때 좋습니다~

오타나 틀린내용 있을시 댓글 부탁드리고 배열,숫자 메서드 링크도 남겨드리겠습니다~

 

▼ 배열 메서드 모음

 

★북마크 필수★ [JavaScript] 배열 메서드 : 카테고리별 완벽 정리

필수 #자바스크립트 >>배열(Array) 메서드즐코하세요~★배열 요소 추가 및 제거 메서드push(요소1, 요소2, ...): 배열의 끝에 하나 이상의 요소를 추가하고, 새 배열의 길이를 반환합니다.let arr = [1, 2,

oxy10023.tistory.com

 

숫자열 메서드 모음 

 

★북마크 필수★ [JavaScript] 숫자 메서드 : 카테고리별 완벽 정리

필수 #자바스크립트 숫자 메서드즐코하세요~★ 숫자 변환 메서드toString(기수): 숫자를 문자열로 변환합니다. 선택적으로 기수를 인자로 받아서 해당 기수로 변환된 문자열을 반환합니다.let num =

oxy10023.tistory.com

 

 

 

728x90
반응형
728x90
반응형

필수 #자바스크립트 숫자 메서드<< 총정리 입니다.

즐코하세요~★


숫자 변환 메서드

toString(기수): 숫자를 문자열로 변환합니다. 선택적으로 기수를 인자로 받아서 해당 기수로 변환된 문자열을 반환합니다.

let num = 123;
console.log(num.toString()); // 출력: "123"
console.log(num.toString(2)); // 출력: "1111011" (2진수)

 

toFixed(소수점 자리 수): 숫자를 고정 소수점 표기법으로 표현하며, 소수점 이하의 자릿수를 지정할 수 있습니다.

let num = 12.34567;
console.log(num.toFixed(2)); // 출력: "12.35"

 

toExponential(유효 숫자 자릿수): 숫자를 지수 표기법으로 표현하며, 유효 숫자의 자릿수를 지정할 수 있습니다.

let num = 123456;
console.log(num.toExponential(2)); // 출력: "1.23e+5"

 

toPrecision(유효 자릿수): 숫자를 지정한 유효 자릿수로 표현하며, 고정 소수점 표기법 또는 지수 표기법을 사용합니다.

let num = 123.456;
console.log(num.toPrecision(4)); // 출력: "123.5"
console.log(num.toPrecision(6)); // 출력: "123.456"

 


숫자 확인 및 비교 메서드

isNaN(값): 값이 NaN(숫자가 아님)인지 확인합니다. NaN일 경우 true를 반환하고, 그렇지 않으면 false를 반환합니다.

console.log(Number.isNaN(123)); // 출력: false
console.log(Number.isNaN(NaN)); // 출력: true

 

isFinite(값): 값이 유한한 숫자인지 확인합니다. 무한대(Infinity 또는 -Infinity)가 아니고, NaN도 아닌 경우 true를 반환합니다.

console.log(Number.isFinite(123)); // 출력: true
console.log(Number.isFinite(Infinity)); // 출력: false

 

isInteger(값): 값이 정수인지 확인합니다.

console.log(Number.isInteger(123)); // 출력: true
console.log(Number.isInteger(123.45)); // 출력: false

 

isSafeInteger(값): 값이 안전한 정수인지 확인합니다. 안전한 정수란 JavaScript에서 표현 가능한 최대 정수 범위 내에 있는 정수입니다.

console.log(Number.isSafeInteger(9007199254740991)); // 출력: true
console.log(Number.isSafeInteger(9007199254740992)); // 출력: false

 


수학적 연산 메서드

Math.abs(값): 값의 절대값을 반환합니다.

console.log(Math.abs(-123)); // 출력: 123

 

Math.ceil(값): 값을 올림하여 가장 가까운 정수를 반환합니다.

console.log(Math.ceil(4.2)); // 출력: 5

 

Math.floor(값): 값을 내림하여 가장 가까운 정수를 반환합니다.

console.log(Math.floor(4.9)); // 출력: 4

 

Math.round(값): 값을 반올림하여 가장 가까운 정수를 반환합니다.

console.log(Math.round(4.5)); // 출력: 5

 

Math.max(값1, 값2, ...): 주어진 숫자들 중에서 가장 큰 값을 반환합니다.

console.log(Math.max(10, 20, 30)); // 출력: 30

 

Math.min(값1, 값2, ...): 주어진 숫자들 중에서 가장 작은 값을 반환합니다.

console.log(Math.min(10, 20, 30)); // 출력: 10

 

Math.pow(밑, 지수): 밑의 값을 지수만큼 거듭제곱한 결과를 반환합니다.

console.log(Math.pow(2, 3)); // 출력: 8

 

Math.sqrt(값): 값의 제곱근을 반환합니다.

console.log(Math.sqrt(16)); // 출력: 4

 

Math.random(): 0 이상 1 미만의 난수를 반환합니다.

console.log(Math.random()); // 출력: 0과 1 사이의 난수

 

Math.trunc(값): 소수점 이하를 제거하고 정수 부분만 반환합니다.

console.log(Math.trunc(4.9)); // 출력: 4

 


형 변환 메서드

Number(값): 값을 숫자로 변환합니다. 문자열, 불리언 등 다양한 값을 숫자로 변환할 수 있습니다.

console.log(Number("123")); // 출력: 123
console.log(Number(true)); // 출력: 1

 

parseInt(문자열, 기수): 문자열을 파싱하여 정수로 반환합니다. 선택적으로 기수를 인자로 받아서 해당 기수로 파싱할 수 있습니다.

console.log(parseInt("123")); // 출력: 123
console.log(parseInt("111", 2)); // 출력: 7 (2진수 111을 10진수로 변환)

 

parseFloat(문자열): 문자열을 파싱하여 부동 소수점 수로 반환합니다.

console.log(parseFloat("123.45")); // 출력: 123.45

 

toFixed(소수점 자리 수): 숫자를 고정 소수점 표기법으로 표현하며, 소수점 이하 자릿수를 지정할 수 있습니다.

let num = 12.34567;
console.log(num.toFixed(2)); // 출력: "12.35"

 


이상입니다. 북마크 해놓으셨다가 필요할 때

적당한거 있는지 둘러볼때 좋습니다~

오타나 틀린내용 있을시 댓글 부탁드리고 배열,숫자 메서드 링크도 남겨드리겠습니다~

 

▼ 배열 메서드 모음 

 

★북마크 필수★ [JavaScript] 배열 메서드 : 카테고리별 완벽 정리

필수 #자바스크립트 >>배열(Array) 메서드즐코하세요~★배열 요소 추가 및 제거 메서드push(요소1, 요소2, ...): 배열의 끝에 하나 이상의 요소를 추가하고, 새 배열의 길이를 반환합니다.let arr = [1, 2,

oxy10023.tistory.com

 

▼ 숫자열 메서드 모음 

 

★북마크 필수★ [JavaScript] 문자열 메서드 : 카테고리별 완벽 정리

JavaScript  문자열의 내용 변경, 검색, 분할, 조합 등의 작업을 수행하는 데 유용한 메서드 모음즐코하세요~ 문자열 검색 및 탐색 메서드indexOf(검색어, 시작 위치): 문자열에서 특정 문자열을 찾아

oxy10023.tistory.com

 

 

728x90
반응형
728x90
반응형

필수 #자바스크립트 >>배열(Array) 메서드<< 총정리 입니다.

즐코하세요~★


배열 요소 추가 및 제거 메서드

push(요소1, 요소2, ...): 배열의 끝에 하나 이상의 요소를 추가하고, 새 배열의 길이를 반환합니다.

let arr = [1, 2, 3];
arr.push(4, 5); // 출력: [1, 2, 3, 4, 5]

 

pop(): 배열의 마지막 요소를 제거하고, 제거된 요소를 반환합니다.

let arr = [1, 2, 3];
arr.pop(); // 출력: 3, 배열: [1, 2]

 

unshift(요소1, 요소2, ...): 배열의 앞에 하나 이상의 요소를 추가하고, 새 배열의 길이를 반환합니다.

let arr = [1, 2, 3];
arr.unshift(0); // 출력: 4, 배열: [0, 1, 2, 3]

 

shift(): 배열의 첫 번째 요소를 제거하고, 제거된 요소를 반환합니다.

let arr = [1, 2, 3];
arr.shift(); // 출력: 1, 배열: [2, 3]

 

splice(시작 인덱스, 제거할 개수, 추가할 요소1, ...): 배열의 특정 위치에서 요소를 추가하거나 제거합니다.

let arr = [1, 2, 3, 4, 5];
arr.splice(2, 1, 10, 20); // 배열: [1, 2, 10, 20, 4, 5]

 


배열 탐색 및 검색 메서드

indexOf(검색할 요소, 시작 인덱스): 배열에서 특정 요소를 검색하여 첫 번째로 발견된 인덱스를 반환합니다. 없으면 -1을 반환합니다.

let arr = [1, 2, 3, 2, 1];
arr.indexOf(2); // 출력: 1

 

lastIndexOf(검색할 요소, 시작 인덱스): 배열에서 특정 요소를 검색하여 마지막으로 발견된 인덱스를 반환합니다. 없으면 -1을 반환합니다.

let arr = [1, 2, 3, 2, 1];
arr.lastIndexOf(2); // 출력: 3

 

includes(요소, 시작 인덱스): 배열에 특정 요소가 포함되어 있는지 확인합니다. true 또는 false를 반환합니다.

let arr = [1, 2, 3];
arr.includes(2); // 출력: true

 

find(콜백 함수): 조건을 만족하는 첫 번째 요소를 반환합니다. 없으면 undefined를 반환합니다.

let arr = [1, 2, 3, 4];
let found = arr.find(element => element > 2); // 출력: 3

 

findIndex(콜백 함수): 조건을 만족하는 첫 번째 요소의 인덱스를 반환합니다. 없으면 -1을 반환합니다.

let arr = [1, 2, 3, 4];
let foundIndex = arr.findIndex(element => element > 2); // 출력: 2

 


배열 변형 및 재구성 메서드

slice(시작 인덱스, 끝 인덱스): 배열의 일부를 추출하여 새로운 배열을 반환합니다. 끝 인덱스는 포함되지 않습니다.

let arr = [1, 2, 3, 4, 5];
let sliced = arr.slice(1, 4); // 출력: [2, 3, 4]

 

concat(배열1, 배열2, ...): 두 개 이상의 배열을 연결하여 새 배열을 반환합니다.

let arr1 = [1, 2];
let arr2 = [3, 4];
let combined = arr1.concat(arr2); // 출력: [1, 2, 3, 4]

 

join(구분자): 배열의 모든 요소를 문자열로 변환한 후, 구분자를 사용하여 하나의 문자열로 결합합니다.

let arr = [1, 2, 3];
let joined = arr.join("-"); // 출력: "1-2-3"

 

reverse(): 배열의 순서를 반대로 바꿉니다.

let arr = [1, 2, 3];
arr.reverse(); // 출력: [3, 2, 1]

 

sort(비교 함수): 배열을 정렬합니다. 기본적으로 문자열로 취급하여 사전식으로 정렬되며, 숫자 정렬 시 비교 함수를 전달해야 합니다.

let arr = [3, 1, 4, 1, 5];
arr.sort((a, b) => a - b); // 출력: [1, 1, 3, 4, 5]

 


배열 반복 및 순회 메서드

forEach(콜백 함수): 배열의 각 요소에 대해 주어진 콜백 함수를 실행합니다. 반환값은 없습니다.

let arr = [1, 2, 3];
arr.forEach(element => console.log(element)); // 출력: 1, 2, 3 (각 요소가 출력됨)

 

map(콜백 함수): 배열의 각 요소를 주어진 콜백 함수로 처리한 후, 그 결과를 모아 새로운 배열을 반환합니다.

let arr = [1, 2, 3];
let mapped = arr.map(element => element * 2); // 출력: [2, 4, 6]

 

filter(콜백 함수): 배열의 각 요소에 대해 주어진 조건을 만족하는 요소만 모아 새로운 배열을 반환합니다.

let arr = [1, 2, 3, 4];
let filtered = arr.filter(element => element > 2); // 출력: [3, 4]

 

reduce(콜백 함수, 초기값): 배열을 순회하며 각 요소에 대해 누적 연산을 수행하여 단일 값을 반환합니다.

let arr = [1, 2, 3, 4];
let sum = arr.reduce((acc, curr) => acc + curr, 0); // 출력: 10

 

reduceRight(콜백 함수, 초기값): reduce()와 동일하게 작동하지만, 배열의 오른쪽(마지막 요소)부터 왼쪽으로 순회합니다.

let arr = [1, 2, 3, 4];
let sum = arr.reduceRight((acc, curr) => acc + curr, 0); // 출력: 10

 

some(콜백 함수): 배열의 요소 중 하나라도 조건을 만족하면 true를 반환합니다.

let arr = [1, 2, 3];
let hasEven = arr.some(element => element % 2 === 0); // 출력: true

 

every(콜백 함수): 배열의 모든 요소가 조건을 만족해야 true를 반환합니다.

let arr = [2, 4, 6];
let allEven = arr.every(element => element % 2 === 0); // 출력: true

 


배열 복사 및 병합

copyWithin(대상 인덱스, 시작 인덱스, 끝 인덱스): 배열 내의 요소를 복사하여 다른 위치에 붙여넣습니다.

let arr = [1, 2, 3, 4, 5];
arr.copyWithin(0, 3); // 출력: [4, 5, 3, 4, 5]

 

fill(값, 시작 인덱스, 끝 인덱스): 배열의 모든 요소를 고정된 값으로 채웁니다.

let arr = [1, 2, 3, 4];
arr.fill(0, 1, 3); // 출력: [1, 0, 0, 4]

 

flat(깊이): 다차원 배열을 평평하게 만들어 1차원 배열로 반환합니다.

let arr = [1, [2, 3], [4, [5]]];
let flattened = arr.flat(2); // 출력: [1, 2, 3, 4, 5]

 

flatMap(콜백 함수): map()과 flat()을 결합한 메서드로, 각 요소에 대해 콜백 함수를 적용한 후 결과를 평평하게 만듭니다.

let arr = [1, 2, 3];
let flatMapped = arr.flatMap(element => [element, element * 2]); // 출력: [1, 2, 2, 4, 3, 6]

 


블로그 오시면 더 있어요~

 

K코딩

걍 누군가는 보겠지, 사실 내가 보려고 글쓰는곳

oxy10023.tistory.com

 

728x90
반응형
728x90
반응형

1편을 안보고 왔으면 보고오는거 추천함

[OSI 7계층 1편]개념 + 알아야 하는 이유(이거보다 쉬운 설명 어디에도 없음)

 

[OSI 7계층 1편]개념 + 알아야 하는 이유(이거보다 쉬운 설명 어디에도 없음)

훌륭한 개발자가 되기위해선 항상 왜?가 중요하지 않겠습니까?OSI 7계층이 뭔지 부터 알아 봅시다. 국제표준기구ISO가 만든 국제네트워크의 표준임, 각 계층이 특정한 기능을 담당해 데이터를 처

oxy10023.tistory.com


OSI 7계층 중에서 2계층인 데이터 링크 계층을 무엇이며

 

우리가 이걸 왜?! 알아야 하는지를

 

쉽고 디테일하게 한번 알아 봅시다


 

데이터 링크 계층의 역할은 크게 3가지 정도임

 

여러분이 택배를 하나 보낼꺼라고 가정해 봅시다

박스

택배를 보내려면 물건이 망가지지 않도록 "박스" 같은거에 포장을 해야하지 않겠습니까?

 

데이터 링크 계층은 데이터를 "프레임"이라는 포장박스에 감싸는 역할을 함

 

왜?! 감싸겠습니까? 맞습니다.

 

데이터를 보낼껀데 데이터가 가다가 손상되면 어떻 할 겁니까? 그래서

 

데이터를 "프레임"이라는 박스로 감싸는 역할을 하는게 데이터 링크 계층입니다.

 

택배 보내기전에 물건을 박스에 포장하는 단계인거죠 근데

택배 운송장

택배를 포장했으면 받는사람 주소가 적혀있는 "운송장"이 붙어있어야지

 

목적지로 택배가 정확하게 전달이 되던가 말던가 할꺼 아닙니까

 

그래서 데이터 링크 계층에 두번째 역할이 이 운송장 주소를 붙히는 겁니다

 

네트워크에서 MAC(맥)주소라는건 택배에서 택배받는곳 주소랑 비슷한데

 

이게 데이터가 어디로 가야 하는지 결정합니다 그렇다면

 

이 MAC주소라는게 뭔지 또 알아야 하지 않겠습니까? 그러면 이해하기 더 쉬울꺼 같습니다

주소 팻말

 

여러분들 집앞에 이런 주소판때기 붙어있죠?

 

그거랑 똑같이 네트워크 통신 비슷한 장치들은 전부다 저런 팻말같은 주소가 붙어 있는데

 

그거를 MAC 주소라고 부릅니다 예를 들어서

 

PC의 랜카드나 스마트폰의 와이파이 모듈, 블루투스 모듈도 외부로 뭔 통신을 하긴하니깐 당연히

 

MAC주소가 할당 되어있음

손상된 택배

 

다시 데이터 링크 계층역활로 넘어가서 여러분 택배가 만약에라도 배송중에 손상되면 어쩝니까?

 

다시 보내줘야 할꺼 아닙니까 그래서

 

데이터 링크 계층의 마지막 역할이 오류 검출과 재전송 입니다

 

택배기사님이 손상된 택배가 있는지 확인할 수 있듯이

 

데이터 링크 계층도 데이터에 오류가 있는지 검출을 합니다 그리고

 

필요하면 데이터를 다시 전송해서 데이터가 정확하게 도착하도록 하는 역활도 합니다


정리하자면

 

데이터 링크 계층은 네트워크에서 데이터를 "프레임"이라는 박스로 안전하게 포장하고

 

MAC주소를 박스에 붙혀서 정확한 주소로 보내주는 역활도 하고

 

데이터에 오류가 있는지 검사해보고 필요하면 데이터 재전송도 해준다 이말입니다

728x90
반응형
728x90
반응형

전 포스팅때 OSI 7계층이 뭔지 개념 잡았었는데 안본사람은 보고오면 이번글 이해하기 편함 링크 걸어줌

[OSI 7계층 1편]개념 + 알아야 하는 이유

 

[OSI 7계층 1편]개념 + 알아야 하는 이유(이거보다 쉬운 설명 어디에도 없음)

훌륭한 개발자가 되기위해선 항상 왜?가 중요하지 않겠습니까?OSI 7계층이 뭔지 부터 알아 봅시다. 국제표준기구ISO가 만든 국제네트워크의 표준임, 각 계층이 특정한 기능을 담당해 데이터를 처

oxy10023.tistory.com


OSI 7계층중 첫번째 물리계층을 알아볼껀데 궁금한사람있음?

 

이런거보면 호기심가지고 궁금해 해야 훌륭한 개발자가 되는거임


물리 계층은 쉽게 설명해서 '길'임

물건을 다른 곳으로 보내려면, 물건이 이동할 수 있는 '길'이 있어야 할꺼 아닙니까

 

자동차는 달릴 수 있는 도로, 기차는 철도, 비행기는 하늘길 이런게 없으면

 

물건을 목적지까지 보낼 수가 없지 않겠습니까

 

물리계층은 네트워크에서 데이터를 주고받을 수 있는 '길'을 만들어 줌

 

여기서 '길'이라는건 전선(랜선), 광섬유(광케이블), 전파(wifi) 같은 물리적인 매체임

 

이 길을 통해서 데이터를 전송할 수 있는 신호(0과 1)가 이동함

 

물리 계층을 만들려면 어째야 겠습니까?

 

인터넷선 연결하거나 와이파이 연결하는게 물리계층 만든거 아니에요? 맞습니다

 

자동차나 기차가 물건을 싣고 이동하듯이, 물리 계층에서는 데이터가

전기 신호나 빛(광케이블)같은 형태의 자동차를 타고 물리적인 길을 통해 가서

 

목적지에 도착함

 

도로가 있어야 차가 다닐 수 있듯이, 물리 계층이 있어야 그 위에서 데이터가 이동을 할꺼 아닙니까

 

어떤 분들은 도로 없이도 자동차는 비포장도로 달릴 수 있는데요? 라고 말 할수 있는데

 

그런 사회 부적격자 비슷한 분들은 여기 없을꺼라고 생각합니다


그럼 물리 계층의 역활을 하는건 무엇이냐면

컴퓨터로 예를 들면 랜카드가 하는거임


즉 정리해보면

 

물리 계층은 네트워크에서 데이터를 주고받기 위해 신호가 지나가는 물리적인 길을 만들어 주는건데

 

이 '길'이란걸 만드는법이 

 

전선(랜선), 광섬유(광케이블), 전파(와이파이) 이런 물리적은 수단을 이용해서

 

그거를 가따가 연결하는게 물리계층 만든거임

 

길이 잘 만들어져 있어야지 데이터가 이동을 해서 전달이 잘 될꺼 아닙니까

728x90
반응형
728x90
반응형

훌륭한 개발자가 되기위해선 항상 왜?가 중요하지 않겠습니까?


OSI 7계층이 뭔지 부터 알아 봅시다.

국제표준기구ISO가 만든 국제네트워크의 표준임,

 

각 계층이 특정한 기능을 담당해 데이터를 처리하고 전달함

 

위 사진을 보면

 

데이터를 다른 컴퓨터나 이런곳으로 보내기 위해서

 

택배 포장하는거랑 비슷하지않음?

 

7계층부터 1계층까지 각 계층을 지나면서 데이터를 보내기위해 택배 포장하듯이 필요한 헤더 정보들이 붙음

 

마지막 1계층까지 가면 00010011011 이런 식으로 컴퓨터가 인식할수있는 언어로 바뀜

 

0과 1로 이루어진 신호로 변환된것이 데이터를 보내기위해서 택배 포장이 끝난거라고 생각하면 쉬움 

 

반대로 수신 측에서는 1계층 컴퓨터언어를 받아서 택배 포장을 해체하듯이

 

헤더 정보들을 제거함 최종 7계층까지 도달하면 원본 데이터를 얻을 수 있음

 

따라서 OSI 7계층 모델은 데이터를 포장하고 해체하는 일련의 과정으로 이해할 수 있음


그럼 이게 왜?! 만들어졌는지 보자면

다국적 택배 시스템을 비유해서 보면 이해하기 쉬움

아프라카 택배?
한국택배
미국택배

각 나라의 택배 회사들이 서로 다른 방법으로 물건을 포장하고 배달함 이러면 문제점이

 

운송장도 다르고 포장 규칙도 다르고 이래서 물건이 중간에 길을 잃거나 잘못 전달되거나 손상되거나 할 수 있겠죠?

세계 곳곳에 택배를 보내려면 모든 나라가 같은 규칙으로 택배를 포장하고 배달해야

 

원활하게 물건을 주고 받을 수 있음

 

택배를 데이터로 바꿔서 데이터를 원활하게 주고 받을려고 국제 네트워크 표준규칙을 만듬

 

그 규칙 이름이 OSI 7계층임

 

택배를 안전하게 배송하기 위해서 여러 단계가 필요함 예를들어서 포장 → 운송 → 세관통과 → 배달

 

OSI 7계층도 이런 식으로 비슷하게 데이터를 보내고 받을 때 각 단계마다 필요한 작업을 정해놨음

 

택배 안전하게 받을려고 = 데이터 원할하게 주고 받을려고 


OSI 7계층 ㅇㅋ 대충 알겠음 그럼 우리가 이걸 왜?! 알아야함?

이건 건물 짓기에 비유하면 쉬움

 

건물을 지을땐 여러 분야의 전문가들이 필요함

 

기초공사하는사람, 목공전문가, 전기전문가, 인테리어전문가 등등 각자 맡은 역활이 있고

 

각 분야 전문가들이 단계별로 투입돼서 건물을 지음

 

OSI 7계층에서도 마찬가지로 데이터를 주고 받는 여러 과정이 나눠져 있음

 

각 계층마다 건물을 짓는 단계처럼 한 계층은 데이터를 전기 신호로 바꾸고,

 

다른 계층은 데이터를 목적지로 안전하게 보냄

 

건물을 짓는 도중에 문제가 생기면 기초공사, 전기, 인테리어 등등 중에서

 

어디가 문제가 생겼는지 알기쉽겠지 않음?

 

OSI 7계층도 알고있으면 어디 계층에서 문제가 생겼는지 쉽게 찾아 내고 해결 할 수 있지 않겠음?

 

결론적으로 네트워크 통신도 각 계층의 역할과 기능을 이해하면 데이터를

 

더안전하고 효율적으로 주고 받을 수 있고, 문제가 생겼을 때 빠르게 해결할 수 있음

 

 

728x90
반응형
728x90
반응형

서버와 클라이언트 진짜 쉽게 설명함

식당을 예로 들어봄

클라이언트

클라이언트는 사용자

식당에서는 손님이 클라이언트임

컴퓨터에서 클라이언트는 장치,프로그램등이 있는데

장치는 데스크톱,노트북,스마트폰 등이 있고

프로그램은 웹 브라우저(ex:크롬)가 있음

 

서버

서버는 식당에서 서빙하는 종업원임

즉 서빙하는 사람을 서버라고 부를 수 있음

 손님이 식당에서 종업원을 불러서 메뉴를 주문하는것이

클라이언트가 서버에 요청하는 행위임

 

데이터베이스

클라이언트의 주문을 받은 서버는 주방장에게 가서

메뉴를 이야기하고 주방장이 만든 음식을

다시 클라이언트에게 가져다 줄꺼임

이게 서버가 하는 역활임

 

이걸 IT스럽게 말하면

클라이언트가 데이터를 요청하면 서버는 데이터베이스에 가서

클라이언트가 요청한 데이터를 가져와서 클라이언트에게 보내주는 역활을 함

 

이게 클라이언트와 서버와 데이터베이스의 관계임

 

서버는 데이터베이스 뿐만아니라

클라이언트와 또다른 클라이언트끼리도 데이터를 주고 받을수있게

연결해주는 역활도함

 

728x90
반응형
728x90
반응형

문제 설명

array의 각 element 중 divisor로 나누어 떨어지는 값을 오름차순으로 정렬한 배열을 반환하는 함수, solution을 작성해주세요.
divisor로 나누어 떨어지는 element가 하나도 없다면 배열에 -1을 담아 반환하세요.

제한사항
  • arr은 자연수를 담은 배열입니다.
  • 정수 i, j에 대해 i ≠ j 이면 arr[i] ≠ arr[j] 입니다.
  • divisor는 자연수입니다.
  • array는 길이 1 이상인 배열입니다.
입출력 예arrdivisorreturn
[5, 9, 7, 10] 5 [5, 10]
[2, 36, 1, 3] 1 [1, 2, 3, 36]
[3,2,6] 10 [-1]
입출력 예 설명

입출력 예#1
arr의 원소 중 5로 나누어 떨어지는 원소는 5와 10입니다. 따라서 [5, 10]을 리턴합니다.

입출력 예#2
arr의 모든 원소는 1으로 나누어 떨어집니다. 원소를 오름차순으로 정렬해 [1, 2, 3, 36]을 리턴합니다.

입출력 예#3
3, 2, 6은 10으로 나누어 떨어지지 않습니다. 나누어 떨어지는 원소가 없으므로 [-1]을 리턴합니다.


나의 풀이

function solution(arr, divisor) {
    var answer = arr.filter( arr => arr % divisor == 0 );
    return answer.length == 0 ? [-1] : answer.sort((a, b)=>{ return a - b })
}

 

filter() : 메서드로 나머지가 0이 되는값만 answer 변수에 넣고
삼항 연산자 : 조건 ? 참일때리턴 : 거짓일때 리턴 을사용해서

나누어 떨어지는게 없으면(answer.length == 0) ? [-1]리턴

나누어 떨어지는게 있으면 sort()메서드를 사용해서 오름차순으로 리턴

 


채점을 시작합니다.
정확성 테스트
테스트 1 통과 (0.06ms, 33.3MB)
테스트 2 통과 (0.06ms, 33.4MB)
테스트 3 통과 (0.07ms, 33.5MB)
테스트 4 통과 (0.07ms, 33.4MB)
테스트 5 통과 (0.07ms, 33.5MB)
테스트 6 통과 (1.90ms, 36.8MB)
테스트 7 통과 (0.16ms, 33.5MB)
테스트 8 통과 (0.05ms, 33.4MB)
테스트 9 통과 (0.18ms, 33.5MB)
테스트 10 통과 (0.15ms, 33.4MB)
테스트 11 통과 (0.08ms, 33.5MB)
테스트 12 통과 (0.10ms, 33.4MB)
테스트 13 통과 (0.22ms, 33.6MB)
테스트 14 통과 (0.29ms, 33.4MB)
테스트 15 통과 (0.13ms, 33.6MB)
테스트 16 통과 (0.12ms, 33.4MB)
채점 결과
정확성: 100.0
합계: 100.0 / 100.0
728x90
반응형

'논리 사고력 훈련' 카테고리의 다른 글

나누어 떨어지는 숫자 배열  (0) 2024.08.26
서울에서 김서방 찾기 indexOf  (0) 2024.08.23
콜라츠 추측  (0) 2024.08.23
두 정수 사이의 합  (0) 2024.08.23
하샤드 수  (0) 2024.08.20

+ Recent posts