Skip to content

๐Ÿง‘โ€๐Ÿซ 4์ฃผ์ฐจ ๋ฉ˜ํ† ๋ง

KimYujeong edited this page Dec 21, 2023 · 2 revisions

๋ฉ˜ํ† ๋ง

โœ”๏ธย ์•„์  ๋‹ค ๋ฐ ์งˆ๋ฌธ

๋ฉ˜ํ† ๋ง ์•„์  ๋‹ค์™€ ๋ฉ˜ํ† ์—๊ฒŒ ํ•˜๊ณ  ์‹ถ์€ ์งˆ๋ฌธ์„ ์‚ฌ์ „์— ์ค€๋น„ํ•ฉ๋‹ˆ๋‹ค.

FE 1๏ธโƒฃย ํ›…์ด ์ปค์งˆ์ˆ˜๋ก ๊ด€๋ฆฌํ•˜๊ธฐ๊ฐ€ ์ ์  ํž˜๋“ค์–ด์ง‘๋‹ˆ๋‹ค.

ํ˜„์žฌ useWebRTC ์•ˆ์ชฝ์˜ ์–ด๋–ค ํ›…์ด ๋งŒ๋“  ์ƒํƒœ๊ฐ€ ๋‹ค๋ฅธ ํ›…์—์„œ ์‚ฌ์šฉ๋˜๊ธฐ๋„ ํ•˜๊ณ , ํ›… ๋ฐ–์˜ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉ๋˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋•Œ ์ƒํƒœ๋ฅผ ์ „์—ญ์œผ๋กœ ๋นผ๋Š”๊ฒŒ ๋งž์„๊นŒ์š”? ์ „์—ญ์œผ๋กœ ๋นผ๋ฉด ์˜์กดํ•˜๋Š” ์ƒํƒœ๋ฅผ ์•Œ์•„๋ณด๊ธฐ ๋” ์–ด๋ ค์งˆ๊ฒƒ๊ฐ™์•„ ๊ณ ๋ฏผ๋ฉ๋‹ˆ๋‹ค.

import { useEffect } from 'react';

import { useControllMedia } from './useControllMedia';
import { useDataChannel } from './useDataChannel';
import { useMedia } from './useMedia';
import { useMediaInfoContext } from './useMediaInfoContext';
import { useRTCPeerConnection } from './useRTCPeerConnection';
import { useSignalingSocket } from './useSignalingSocket';
import { useSocket } from './useSocket';

export function useWebRTC(roomName: string) {
  const { socketEmit } = useSocket('WebRTC');

  const { mediaInfos } = useMediaInfoContext();
  const { localVideoRef,
    remoteVideoRef,
    localStreamRef,
    cameraOptions,
    audioOptions,
    getMedia,
    getAudiosOptions,
    getCamerasOptions,
  } = useMedia();

  const { peerConnectionRef, makeRTCPeerConnection, closeRTCPeerConnection } = useRTCPeerConnection({
    roomName,
    remoteVideoRef,
  });
  const { mediaInfoChannel, chatChannel, initDataChannels, closeDataChannels } = useDataChannel({
    peerConnectionRef,
  });

  const { addTracks, changeMyAudioTrack, changeMyVideoTrack, toggleAudio, toggleVideo } = useControllMedia({
    localStreamRef,
    peerConnectionRef,
    localVideoRef,
    mediaInfoChannel,
    getMedia,
  });

  const negotiationDataChannels = () => {
    closeRTCPeerConnection();
    closeDataChannels();
    makeRTCPeerConnection();
    initDataChannels();
    addTracks();
  };

  const { initSignalingSocket } = useSignalingSocket({
    roomName,
    peerConnectionRef,
    negotiationDataChannels,
  });

  useEffect(() => {
    const initOnMount = async () => {
      await getMedia({});
      initSignalingSocket();
      makeRTCPeerConnection();
      initDataChannels();
      addTracks();
      socketEmit('joinRoom', roomName);
    };

    initOnMount();

    return () => {
      closeRTCPeerConnection();
      closeDataChannels();
    };
  }, []);

  return {
    cameraOptions,
    audioOptions,
    localVideoRef,
    remoteVideoRef,
    mediaInfoChannel,
    chatChannel,
    mediaInfos,
    toggleAudio,
    toggleVideo,
    addTracks,
    changeMyAudioTrack,
    changeMyVideoTrack,
    getAudiosOptions,
    getCamerasOptions,
    getMedia,
  };
}

๐Ÿ’ก ๋‹ต๋ณ€ ) hook์—์„œ ๋„ˆ๋ฌด ๋งŽ์€ ๊ฒƒ๋“ค์„ ์ฒ˜๋ฆฌํ•œ๋‹ค. ๋ชจ๋“ˆํ™”ํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฑด ์–ด๋–จ๊นŒ?

  • ํ•ด๋‹น ๋ถ€๋ถ„์„ ๋ชจ๋“ˆ๋กœ ๋นผ์„œ ๊ด€์‹ฌ์‚ฌ๋ฅผ ๋ถ„๋ฆฌํ•˜๋ฉด ์ข‹์„ ๋“ฏํ•˜๋‹ค.
  • ํ›…์˜ ์˜์กด๊ด€๊ณ„๊ฐ€ ๋„ˆ๋ฌด ๋†’์•„์ง€๋ฉด ์ถ”์ ํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค.
  • ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ๋”ฐ๋ผ ์ด๋ฅผ ๋ถ„๋ฆฌํ•ด๋ณด์ž!

FE 2๏ธโƒฃ socket.io์—์„œ join

๐Ÿ’ก ๋‹ต๋ณ€ ) hoxy ์žฌ์—ฐ๊ฒฐ ์ด์Šˆ..?


BE 1๏ธโƒฃ ์‹œ๊ทธ๋„๋ง ์„œ๋ฒ„๊ฐ€ ์›น์†Œ์ผ“ ์š”์ฒญ์„ ๋ฐ›์ง€ ๋ชปํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค ๐Ÿ˜‚

ํ˜„์žฌ ์ด 3๊ฐœ์˜ ๋„์ปค ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋„์šฐ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

- nginx
- was 3000
- signal 3001

nginx์—์„œ was์™€ signal ์„œ๋ฒ„๋กœ ํ”„๋ก์‹œ ํ•˜๋Š”๋ฐ was๋กœ http ์š”์ฒญ์„ ํ”„๋ก์‹œ ํ•˜๋Š” ๊ฒƒ์€ ๋˜์ง€๋งŒ, signal ์„œ๋ฒ„๋กœ ์›น์†Œ์ผ“ ์š”์ฒญ์„ ํ”„๋ก์‹œ ํ•˜๋Š” ๊ฒƒ์ด ๋™์ž‘ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด๊ฑด nginx ํŒŒ์ผ์ž…๋‹ˆ๋‹ค. ์›น์†Œ์ผ“ ์š”์ฒญ์ด๋ฏ€๋กœ upgrade ๋ฅผ ๋„ฃ์–ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

  • nginx ์„ค์ • ํŒŒ์ผ
    server {
        listen 80;
        server_name was.tarotmilktea.com;
        ...
    
        location /signal { # signal ์„œ๋ฒ„
            proxy_pass http://signal:3001;
            proxy_redirect   default;
            proxy_http_version 1.1; # ๋ฒ„์ „ ๋ช…์‹œ
            proxy_set_header Upgrade $http_upgrade; # upgrade ์„ค์ •
            proxy_set_header Connection "upgrade";  # upgrade ์„ค์ •
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    
        location / {
            proxy_pass http://was:3000;
            proxy_redirect   default;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    
        access_log /var/log/nginx/nest-app-access.log;
        error_log /var/log/nginx/nest-app-error.log;
    }
    
    server {
        listen 443 ssl;
        server_name was.tarotmilktea.com;
        ...
        location /signal { # signal ์„œ๋ฒ„
            proxy_pass http://signal:3001;
            proxy_redirect   default;
            proxy_http_version 1.1; # ๋ฒ„์ „ ๋ช…์‹œ
            proxy_set_header Upgrade $http_upgrade; # upgrade ์„ค์ •
            proxy_set_header Connection "upgrade";  # upgrade ์„ค์ •
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    
        location / { 
            proxy_pass http://was:3000;
            proxy_redirect   default;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    
        access_log /var/log/nginx/nest-app-access.log;
        error_log /var/log/nginx/nest-app-error.log;
    }

docker ps ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค. 3๊ฐœ์˜ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋ชจ๋‘ ์ž˜ ๋– ์žˆ์Šต๋‹ˆ๋‹ค.

CONTAINER ID   IMAGE        COMMAND                  CREATED             STATUS             PORTS                                      NAMES
447a1f84b6bb   app_nginx    "/docker-entrypoint.โ€ฆ"   43 minutes ago      Up 43 minutes      0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp   app_nginx_1
77870bb6c78c   app_signal   "docker-entrypoint.sโ€ฆ"   55 minutes ago      Up 55 minutes      3001/tcp                                   app_signal_1
3a5e3e02a3a8   app_was      "docker-entrypoint.sโ€ฆ"   About an hour ago   Up About an hour   3000/tcp

nginx ์ปจํ…Œ์ด๋„ˆ์— ๋“ค์–ด๊ฐ€์„œ http ๋ฐ wss ์š”์ฒญ์„ ๋ณด๋‚ธ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค.

# http ์š”์ฒญ (GET / ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์—†์–ด์„œ Not Found๊ฐ€ ๋–ด์Šต๋‹ˆ๋‹ค)
root@447a1f84b6bb:/$ curl http://signal:3001
{"message":"Cannot GET /","error":"Not Found","statusCode":404}

# wss ์š”์ฒญ (curl๋กœ wss ์š”์ฒญ ๋ณด๋‚ด๊ธฐ??)
root@447a1f84b6bb:/$ curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Host: was.tarotmilktea.com" http://signal:3001
curl: (52) Empty reply from server

๐Ÿ’ก ๋‹ต๋ณ€ ) ๋๋‚˜๊ณ  ๋ด…์‹œ๋‹ค(?)


์ง„ํ–‰์ƒํ™ฉ

  • ์ฑ„ํŒ…๋ฐฉ ๊ฐœ์„คํ•˜๊ธฐ๋ฅผ ๋ˆŒ๋ €์„ ๋•Œ ์‹œ์ž‘๋˜๋Š” ์‚ฌ์šฉ์ž ๊ฐ„ ์‹ค์‹œ๊ฐ„ ํ™”์ƒ ์ฑ„ํŒ…์—์„œ ํ•„์ˆ˜ ๊ธฐ๋Šฅ๋“ค ์™„๋ฃŒ
    • ๋‹‰๋„ค์ž„/ํ”„๋กœํ•„ ์„ค์ • ๋“ฑ ์„ธ๋ถ€ ๊ธฐ๋Šฅ๋งŒ ๋‚จ์Œ
  • ๊ฐœ๋ฐœ ๋ฐ ์œ ์ง€๋ณด์ˆ˜๋ฅผ ์œ„ํ•ด winston ๋กœ๊ฑฐ ์ ์šฉํ•˜์—ฌ ๋ ˆ๋ฒจ๋ณ„๋กœ ๋กœ๊ทธ ๋‚จ๊ธฐ๊ธฐ
    • ์ถ”ํ›„ volume ์„ ํ™œ์šฉํ•˜์—ฌ ํ˜ธ์ŠคํŠธ ์„œ๋ฒ„์— ๋กœ๊ทธ ๋‚จ๋„๋ก ์ˆ˜์ • ์˜ˆ์ •
  • signal ์„œ๋ฒ„ express์—์„œ nest๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜

๋‹ค์Œ์ฃผ ๊ณ„ํš

  • BE : ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ (๋ธ”๋ฃจ/๊ทธ๋ฆฐ ์ „๋žต)
  • FE : ์‹ค์‹œ๊ฐ„ ํ™”์ƒ ์ฑ„ํŒ… ์„ธ๋ถ€ ๊ธฐ๋Šฅ ๋งˆ๋ฌด๋ฆฌ
  • ๋ฒ„๊ทธ ์žก๊ธฐ
    • Object Storage ์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ
  • FE : SEO + ๋„ค์ด๋ฒ„/๊ตฌ๊ธ€์— ์‚ฌ์ดํŠธ ๋“ฑ๋กํ•˜๊ธฐ
  • ์ฝ”๋“œ ๋ฆฌํŒฉํ† ๋ง
    • ์ƒˆ๋กœ ๋งŒ๋“  ๋ฒ„ํŠผ์œผ๋กœ ๊ต์ฒด
    • ๋น„์Šทํ•œ ๊ฒƒ๋ผ๋ฆฌ ํด๋” ์ •๋ฆฌ
    • ์ƒํƒœ ๊ด€๋ฆฌ ๊ด€๋ จ
    • ํŒฉํ† ๋ฆฌ ํ™œ์šฉ
    • ๋ฉ˜ํ† ๋ง ํ”ผ๋“œ๋ฐฑ ๋ฐ˜์˜
  • ์—๋Ÿฌ ํ•ธ๋“ค๋ง
  • FE : ์„ฑ๋Šฅ ์ตœ์ ํ™” (๋ Œ๋”๋ง ์ตœ์ ํ™” & ๋กœ๋”ฉ์†๋„ ์ตœ์ ํ™”) โ‡’ react developer tools & lighthouse ํ™œ์šฉํ•˜๊ธฐ
  • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ
  • BE : ๋กœ๊ทธ ๊ด€๋ฆฌ
  • FE : ์›น ์ ‘๊ทผ์„ฑ (์•„๋งˆ 6์ฃผ์ฐจ)
  • ๋ฌธ์„œํ™” ๐Ÿฅบ (์•„๋งˆ 6์ฃผ์ฐจ)

โœ”๏ธย ๋ฉ˜ํ† ๋ง ๋‚ด์šฉ

๋ฉ˜ํ† ๋ง ์‹œ๊ฐ„์— ๋‚˜๋ˆˆ ์ด์•ผ๊ธฐ๋ฅผ ๊ธฐ๋กํ•ด๋ณด์„ธ์š”.

๐Ÿ“Œ ๊ณตํ†ต ์ฝ”๋ฉ˜ํŠธ

  • ์ปค๋ฐ‹์— ์ด์œ ๋ฅผ ๋‹ฌ์ž
  • ๊ธฐ์ˆ ์  ๋„์ „ ๊ธ€๋กœ ๊ณต์œ ํ•ด๋ณด๋Š” ๊ฒŒ ์–ด๋–จ๊นŒ?
  • ํ•จ์ˆ˜์˜ ์ด๋ฆ„์„ ๋ณด๊ณ  ์˜ˆ์ƒ์ด ๋˜๋ฉด ์ข‹๊ฒ ๋‹ค.

๐Ÿ“Œ FE ์ฝ”๋ฉ˜ํŠธ

  • hook์œผ๋กœ๋งŒ ์ฒ˜๋ฆฌํ•˜๋ ค๊ณ  ํ•˜์ง€๋ง๊ณ  ๋ชจ๋“ˆํ™”๋ฅผ ํ•˜์ž
    • ํ›…์˜ ๋™์ž‘์›๋ฆฌ๋ฅผ ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๋ฉด ๋‚˜์ค‘์— ๊ผฌ์ผ ์ˆ˜ ์žˆ์Œ
  • ์งˆ๋ฌธ ) ๋ฐ์ดํ„ฐ ์ฑ„๋„๋กœ ์ฑ„ํŒ… ๊ตฌํ˜„ํ–ˆ๋Š”๋ฐ ์–ด๋–ค ์ ์ด ์ข‹์•˜๋‚˜?
    • ๋‹ต๋ณ€ ) ์†Œ์ผ“๊ณผ ๋ณ„ ์ฐจ์ด๊ฐ€ ์—†์—ˆ๋‹ค.
    • ๋ฐ์ดํ„ฐ ์ฑ„๋„์€ ํŒŒ์ผ๋„ ์ฃผ๊ณ  ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์  ์กด์žฌ
    • ๋ฐ์ดํ„ฐ ์ฑ„๋„์€ ์ปค๋„ฅ์…˜์„ ๋งบ์„๋•Œ๋งˆ๋‹ค ๋ชจ๋‘ ๋‹ค์‹œ ํ˜‘์ƒ์„ ์ง„ํ–‰ํ•ด์•ผ ํ•˜๋Š”๊ฒŒ ๋งž๋‹ค.
  • ์–ด๋–ค ํ›…์ธ์ง€ ๋„๋ฉ”์ธ ๋ณ„๋กœ ๊ตฌ๋ถ„์„ ํ•ด๋ณด๋Š”๊ฒŒ ์ข‹๊ฒ ๋‹ค!
    • ์ปดํฌ๋„ŒํŠธ์—์„œ controlled , uncontrolled ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žˆ๋‹ค.
    • matariel ui ๋“ฑ์„ ์“ด๋‹ค๋ฉด ๋žฉํ•‘์ด ๋งŽ์ด ๋  ์ˆ˜๊ฐ€ ์žˆ๊ณ  ๊นŠ์ด๊ฐ€ ๊นŠ์–ด์ง€๋ฉด ์–ด๋–ค ์• ๊ฐ€ ์ƒํƒœ๋ฅผ ๋ฐ”๊พธ๋Š”์ง€ ๋ชจ๋ฅธ๋‹ค.
    • ์œ ๋ช…ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ์ด ๋‘ ๊ฐœ์— ๋Œ€ํ•œ ๊ธฐ์ค€์„ ์ƒ๊ฐํ•ด๋ณด๋ฉด ๋„์›€์ด ๋  ๊ฒƒ ๊ฐ™๋‹ค.
  • ํ™ˆ โ†’ Chat์œผ๋กœ ๊ฐ€๋Š” ๋ถ€๋ถ„ ์†Œ์ผ“ ์—ฐ๊ฒฐ ๊ณ ๋ ค
    • ํ˜„์žฌ ์†Œ์ผ“ ์—ฐ๊ฒฐ์„ ๋งบ๊ณ  ๊ฐ€๊ณ  ์žˆ์Œ
  • ๋ฆฌ์•กํŠธ ์ฟผ๋ฆฌ๋Š” ์„ ์–ธ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜๋„ ์žˆ๊ณ  ๊ฐ€์ ธ์˜ค๋Š” ๋กœ์ง์„ ํŽธํ•˜๊ฒŒ ๋ถ„๋ฆฌ ๊ฐ€๋Šฅ! ์žฌ์‹œ๋„ ๋กœ์ง๋„ ํŽธํ•˜๊ฒŒ ์งค ์ˆ˜ ์žˆ๋‹ค. ์˜คํ”„๋ผ์ธ์ผ ๋•Œ ์บ์‹œ๋กœ ๋„ค์ดํ‹ฐ๋“œ ์•ฑ์ฒ˜๋Ÿผ ์ž‘๋™ํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค!
  • ์•„์‰ฌ์šด ์ 
    • ์•ŒํŒŒ๋ฒณ์ˆœ ์ •๋ ฌ์ด๋ผ ์ด๋ฆ„๋งŒ ๊ฐ€์ง€๊ณ  ์ถ”๋ก ํ•˜๊ธฐ ํž˜๋“ฌ โ†’ ๋„๋ฉ”์ธ๋ณ„๋กœ ๋‚˜๋ˆ„์ž?
    • ์ตœ๋Œ€ํ•œ useref ๋“ฑ์„ ์‚ฌ์šฉํ•œ uncontrolled ๋ฐฉ์‹์œผ๋กœ ํ›…์„ ๊ฐœ์„ ํ•ด์„œ ์‚ฌ์ด๋“œ์ดํŽ™ํŠธ๋ฅผ ์ค„์ด๋Š” ๊ฑธ ์ถ”์ฒœ
    • ํ•จ์ˆ˜์˜ ์ด๋ฆ„์„ ๋ณด๊ณ  ๋™์ž‘์ด ์˜ˆ์ƒ์ด ๋˜์–ด์•ผํ•˜๋Š”๋ฐ ์˜ˆ์ƒ์ด ์•ˆ๋˜๋Š” ๋ถ€๋ถ„์ด ๊ฐ„ํ˜น ๋ณด์ž„
      • useSocket
    • ํ™ˆ์—์„œ ์ฑ„ํŒ…์œผ๋กœ ๊ฐˆ ๋•Œ ์†Œ์ผ“์„ ์—ฐ๊ฒฐํ•˜๊ณ  ๋„˜์–ด๊ฐ€๋Š” ๋ฌธ์ œ โ†’ ์ˆ˜์ • ์ถ”์ฒœ
      • ํŽ˜์ด์ง€์—์„œ ์ƒˆ๋กœ๊ณ ์นจํ•˜๋ฉด ์†Œ์ผ“ ์—ฐ๊ฒฐ Init X
  • useQuery vs useSuspendQuery

๐Ÿ“Œ BE ์ฝ”๋ฉ˜ํŠธ

  • ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๊นŠ์ด๊ฐ€ ์ข€ ๊นŠ๋‹ค.
    • catch๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ํ•ด๋„ ๊ดœ์ฐฎ๋‹ค.
    • early return๋„!
    • ๋ฏธ๋“ค์›จ์–ด๋กœ exception์„ ๋ฐ›์•„์„œ ์ฒ˜๋ฆฌ
    • ๋ฏธ๋“ค์›จ์–ด๋กœ ๋กœ๊ทธ๋ฅผ ์ฐ์–ด๋ณด์ž.
  • clova ๊ด€๋ จ ์ƒ์ˆ˜ ์ค‘์— ๋ฐฐ์—ด์ด ์žˆ๋‹ค.
    • ๋ฐฐ์—ด์€ ์ˆ˜์ •์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ์ •๋ง ์ƒ์ˆ˜๋กœ ๋งŒ๋“ค์–ด๋ณด๋Š” ๊ฒŒ ์–ด๋–จ๊นŒ?
  • ํŒฉํ† ๋ฆฌ๋ฅผ ํ™œ์šฉํ•ด๋ณด์ž
    • DTO, entity ์ƒ์„ฑํ•  ๋•Œ
    • URL ์ƒ์„ฑํ•  ๋•Œ
  • null ์— ์˜๋ฏธ๋ฅผ ๋ถ€์—ฌํ•ด๋ณด์ž (undefined vs. null)
    • ์—†์œผ๋ฉด exception ์ฒ˜๋ฆฌ

๐Ÿ“Œ ๊ธฐํƒ€

  • 17์กฐ ์ฑ„ํŒ… ๊ด€๋ จ ์ฝ”๋ฉ˜ํŠธ : ๋ฉ˜ํ† ๋‹˜์˜ ๊ฒฝ์šฐ, http2์˜ keep alive ๋กœ ์‹ค์‹œ๊ฐ„ ์ฑ„ํŒ… ๊ตฌํ˜„ํ–ˆ๋‹ค.
  • FE์™€ BE ๊ณตํ†ต ๋ชจ๋“ˆ ๊ด€๋ฆฌ โ‡’ 17์กฐ : turbo์˜ internal package
    • package.json ์˜ main , types ์•Œ์•„๋ณด๊ธฐ
    • eslint ๋™์ž‘ ์ฐพ์•„๋ณด๊ธฐ (ex. ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์–ด๋–ป๊ฒŒ ์ฐพ๋Š”์ง€)
    • https://toss.tech/article/commonjs-esm-exports-field
    • ํ•˜์ง€๋งŒ ์‹œ๊ฐ„ ๋งŽ์ด ์žก์•„๋จน์œผ๋‹ˆ ๋‚˜์ค‘์œผ๋กœ ๋ฏธ๋ฃฐ ๊ฒƒ
  • mock : https://github.com/google/intermock
  • graphQL โ‡’ ๋ฐฑ/ํ”„๋ก ํŠธ api ๋ถ„์Ÿ์„ ์ด์ƒ์ ์œผ๋กœ ํ’€์–ด๋‚ผ ์ˆ˜ ์žˆ์Œ!
  • ngrok, cloud tunnel ๋‚ด ๋กœ์ปฌ์„ ์„œ๋ฒ„์ฒ˜๋Ÿผ ๋„์šธ์ˆ˜์žˆ๋‹ค. ํด๋ผ์šฐ๋“œํ”Œ๋ ˆ์–ด ํ„ฐ๋„ โ‡’ pc ip๊ฐ€ ํ”„๋ก์‹œ๊ฐ€ ๋ผ์„œ ์™ธ๋ถ€์—์„œ ์ ‘์†์ด ๊ฐ€๋Šฅํ•˜๋‹ค. โ†’ ๋‚ด๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋„๋ฉ”์ธ๋„ ๋ถ™์ผ ์ˆ˜ ์žˆ๋‹ค.

โœ”๏ธย ์ฒดํฌ๋ฆฌ์ŠคํŠธ

์ด๋ฒˆ ์ฃผ ๋ฉ˜ํ† ๋ง์—์„œ ์ด์•ผ๊ธฐ ๋‚˜๋ˆ„๋ฉด ์ข‹์„ ์ฃผ์ œ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ ํŒ€์˜ ์ƒํ™ฉ์€ ์–ด๋–ค๊ฐ€์š”? ๋ฉ˜ํ† ๋‹˜๊ณผ ์ด์•ผ๊ธฐ ๋‚˜๋ˆˆ ํ›„ ์…€ํ”„ ์ฒดํฌํ•˜๊ณ , ๊ทธ ์ด์œ ๋ฅผ ์ž‘์„ฑํ•ด๋ณด์„ธ์š”. ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์€ ํ•ญ๋ชฉ์ด ์žˆ๋‹ค๋ฉด ์ง์ ‘ ์ถ”๊ฐ€ํ•ด๋„ ์ข‹์Šต๋‹ˆ๋‹ค.

  • ๊ธฐ์ˆ ์  ๋„์ „ ๊ณผ์ œ ์ˆ˜๋ฆฝ์ด ๋˜์—ˆ๋‹ค.
  • ํ˜„์‹ค์„ฑ ์žˆ๋Š” ๊ณ„ํš ์ˆ˜๋ฆฝ์ด ๋˜์—ˆ๋‹ค.
  • ํ”„๋กœ์ ํŠธ ๊ธฐํš๊ณผ ์„ค๊ณ„์˜ ๋ผˆ๋Œ€๊ฐ€ ๋‚˜์™”๋‹ค.

๐Ÿ’ฆ ์šฐ๋‹นํƒ•ํƒ• ์ด์Šˆ ํ•ด๊ฒฐ๊ธฐ

BE

FE

FE/BE

๐Ÿง‘โ€๐Ÿซ ๋ฉ˜ํ† ๋ง ์ผ์ง€

๐Ÿ“ข ํšŒ์˜๋ก

๐Ÿ’ฌ ์Šคํฌ๋Ÿผ

๐Ÿ’ญ ํŒ€ ํšŒ๊ณ 

๐Ÿ’ญ ๊ฐœ์ธ ํšŒ๊ณ 

๐Ÿƒ Ongoing Project

Clone this wiki locally