오늘의 목표

더보기

✔️ 프로그래머스 코테 문제 풀기

✔️ 팀프로젝트 회의

 


⏱️ 오늘의 일정

프로그래머스 코테 문제 풀기

팀 프로젝트 회의


📜 프로그래머스 코테 문제 풀기

 

Jaden 문자열 만들기

 

https://github.com/YamSaeng/AlgorithmCodingTest/tree/main/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4/2/12951.%E2%80%85JadenCase%E2%80%85%EB%AC%B8%EC%9E%90%EC%97%B4%E2%80%85%EB%A7%8C%EB%93%A4%EA%B8%B0

 

AlgorithmCodingTest/프로그래머스/2/12951. JadenCase 문자열 만들기 at main · YamSaeng/AlgorithmCodingTest

This is an auto push repository for Baekjoon Online Judge created with [BaekjoonHub](https://github.com/BaekjoonHub/BaekjoonHub). - YamSaeng/AlgorithmCodingTest

github.com

 

function solution(s) {
    var answer = '';

    let isFirst = false;
    for (let i = 0; i < s.length; i++) {
        if (s[i] === ' ') {
            answer += ' ';
            isFirst = false;
        }
        else if (isFirst === false) {
            answer += s[i].toUpperCase();
            isFirst = true;
        }
        else {
            answer += s[i].toLowerCase();
        }
    }

    return answer;
}

 

문제에서 설명해준 대로 코드를 구성하니 쉽게 풀 수 있었다.

 

📜 팀프로젝트 회의

 

앞서 언급한대로 새로운 팀프로젝트가 시작됐다.

이번 팀 프로젝트는 타워 디펜스 게임을 만드는 프로젝트다.

 

기본적으로 캠프에서 타워 디펜스를 제공해주고, 팀에서는 그에 해당하는 서버를 만드는 것을 목표로 삼는다.

 

와이어 프레임 ( 화면 구성 )

 

회원가입과 로그인은 express를 이용해 처리해주고,

메인인 게임에 들어가면 서버와는 웹소켓을 활용해 통신해 주도록 구성했다.

 

이번 팀 프로젝트는 총 6명이서 진행하는데,

맡아야할 파트를 나누는게 참 어려웠다. 긴 회의를 거친 끝에 다음과 같이 분배했다.

 

 

 

나는 회원가입과 로그인 파트를 맡았다.

 

 

 

 

회원가입한 유저들을 관리하는 users 테이블과

게임 시작할때 게임 초기화에 필요한 데이터가 들어있는 initGame 테이블,

몬스터에 대한 데이터가 들어있는 monster 테이블

타워에 대한 정보가 들어있는 tower 테이블

타워를 업그레이드 할때 능력치의 비율이 들어있는 upgrade 테이블로 DB를 구성했다.

 

사실상 insert 하고 delete 하는 테이블은 users 테이블 하나고 나머지는 모두 데이터 자체가 들어있는 테이블이다.

 

 

내일까지 회원가입과 로그인을 완성해 다른 팀원분들이 테스트 할 수 있도록 준비해야겠다!!

 

오늘의 목표

더보기

✔️ CS 정리

✔️ 개인과제 완성


⏱️ 오늘의 일정

CS 정리

개인과제 완성


📜 CS 정리

IP 주소의 체계, 사설망과 공인망에 대해 정리했다.

2024.10.07 - [CS] - [CS] IP 주소의 체계, 사설망, 공인망

 

[CS] IP 주소의 체계, 사설망, 공인망

IP 주소네트워크에서 통신을 위한 일련의 규칙이자 약속( 통신규약 )들이 존재하며, 이를 프로토콜이라고 부른다.그 중 인터넷 통신을 위한 프로토콜도 존재하는데 대표적인 것이 바로 IP다.IP는

program-yam.tistory.com

 

 

📜 개인 과제 완성

 

10월 7일 정오까지 개인 과제 제출시간이라서 시간에 맞게 제출했다.

 

https://github.com/YamSaeng/DinoRunner

 

GitHub - YamSaeng/DinoRunner

Contribute to YamSaeng/DinoRunner development by creating an account on GitHub.

github.com

 

기존에 설명했던 https://dinorunner.com/ko/

 

크롬 다이노 게임 온라인

T-Rex Dinosaur (Dinosaur Google) - 인터넷이 없을 때 Chrome 브라우저에 숨겨진 게임의 복제본. 시작하려면 스페이스바를 누르십시오. 스페이스바 또는 위쪽 화살표와 아래쪽 화살표(↓)를 사용하여 공룡

dinorunner.com

 

위 게임에서 추가한 부분은 다음과 같다.

Update() {
        this.userScoreUpdateTime -= 15;

        // 1초마다 서버에서 Score 계산
        if (this.userScoreUpdateTime < 0) {
            this.userScoreUpdateTime = USER_SCORE_UPDATE_TIME;

            if (this.users.length > 0) {
                // 접속중인 유저들을 순환하면서 스테이지에 맞게 점수 증가
                this.users.forEach(user => user.Update());

                // HighScore를 갱신
                for (let i = 0; i < this.users.length; i++) {
                    if (this.users[i].score > this.HighScore.score) {
                        this.HighScore.score = this.users[i].score;
                        this.HighScore.userId = this.users[i].userUUID;
                        
                        this.users[i].socket.emit("response", {
                            packetType: S2C_PACKET_TYPE_NEW_HIGH_SCORE,
                            data: { userId: this.HighScore.userId, score: this.HighScore.score }
                        });
                    }                  
                }                
            }
        }       
    }

서버에서 매 시간 1초마다 접속중인 유저들을 순환하면서 점수를 스테이지에 맞게 증가시켜준다.

이처럼 매 시간마다 서버에서 반복하면서 로직을 처리하는 방식에 대한 것을 튜터님에게 따로 물어봤다.

 

지금처럼 접속하는 유저가 적을 경우에는 서버에 부담이 가지 않아 위처럼 구성해도 되지만, 

서버에 접속하는 유저가 많아지면 서버에 부담이 가서 위와 같은 방법은 추천하지 않는다고 피드백을 받았다.

 

대신 점수를 검증하는 부분을 클라가 점수를 쌓기 시작한 시간과 어떤 특정한 점수에 도달했을 때 시간을

서버에 전송해서 서버는 두 시간 차를 토대로 점수를 계산해 인증해주는 방식이 서버에 부담이 가지 않는 방식이라는 말도 추가로 피드백을 받았다.

 

 

나는 기본적으로 서버에서 모든 로직을 담당하고 그냥 클라는 서버에서 처리한 결과를 보여주는 방식으로만 생각하긴 했는데, 물론 내 생각처럼 구성하는 서버도 존재한다고는 했다.

 

아마도.. 위와 같은 부분을 잘 구분( 서버에서 처리할건지, 클라에서 처리할 건지) 하고 설정하는 것이 기술이라고 생각 할 수 있긴 할 것 같다.

 

Update() {
        this.rankingScoreUpdateTime -= 15;
        if (this.rankingScoreUpdateTime < 0) {
            // 업데이트한 랭킹 점수를 접속 중인 유저들에게 전달                        
            this.rankingScoreUpdateTime = RANK_SCORE_UPDATE_TIME;
            let scoreArray = this.users.map((user) => {
                const score = [];
                score.push({
                    userUUID: user.userUUID,
                    score: user.score,
                    currentStage: user.currentStage
                });
                return score;
            });

            this.BroadCast({ packetType: S2C_PACKET_TYPE_RANK_SCORE_UPDATE, data: scoreArray });;
        }
    }

 

유저들의 점수를 계산하고 나서는 BroadCast를 활용해 유저들의 점수를 접속중인 모든 유저들에게 전달한다.

 

 

keydown = (event) => {
        if (event.code === "Space") {
            this.jumpPressed = true;
        }

        if (event.code === "ArrowLeft") {
            this.speed = -PLAYER_SPEED;
        }

        if (event.code === "ArrowRight") {
            this.speed = PLAYER_SPEED;
        }
    };

 

좌우 키를 입력하면 speed에 값을 줘서 공룡 캐릭터를 움직일 수 있도록 변경했다.

 

keydown = (event) => {       
        // A키를 누르면 불꽃 발사
        if (event.code === "KeyA") {
            if (this.fireAttackTimer <= 0 && this.fireCount > 0) {
                let game = Game.GetInstance();
                if (game != null) {
                    this.fireCount--;
                    game.jobQue.push(new Job(JOB_TYPE_CREATE_OBJECT_FIRE,
                        OBJECT_TYPE_FIRE, this.x, this.y));

                    this.fireAttackTimer = FIRE_ATTACK_TIMER;
                }
            }
        }

        // R키를 누르면 불꽃 발사
        if (event.code === "KeyR") {
            this.fireCount = FIRE_COUNT;
        }
    };

 

'A'키를 입력하면 불꽃을 발사할 수 있도록 하고, R키를 누르면 불꽃을 재장전한다.

 

// 불꽃 관리
class FireController {
    constructor(ctx, scaleRatio, itemController) {
        this.fireId = 1; // 관리중인 fire 구분하기 위한 id 값
        this.fires = [];
        this.ctx = ctx;
        this.canvas = ctx.canvas;
        this.scaleRatio = scaleRatio;
        this.itemController = itemController;
    }

    // 불꽃 생성
    CreateFire(spawnXPosition, spawnYPosition) {
        const newFire = new Fire(this.fireId, this.ctx, this.scaleRatio);
        newFire.SetPosition(spawnXPosition, spawnYPosition);

        this.fires.push(newFire);
        this.fireId++;
    }

    // 불꽃 업데이트
    Update(gameSpeed, deltaTime) {       
        // 충돌한 불꽃이 있으면 제거
        this.fires.forEach((fire)=>{
            if(fire.isCollide == true)
            {
                this.fires = this.fires.filter(collideFire => collideFire.id !== fire.id);
            }
        })

        this.fires.forEach((fire) => {
            fire.update(gameSpeed, deltaTime);
        });
        
        this.fires = this.fires.filter(fire => fire.x < 800);
    }

    // 매개변수로 받은 sprites 배열과 충돌하는지 확인
    CollideWithMultiple(sprites) {
        let isCollider = false;

        for (let i = 0; i < this.fires.length; i++) {
            for (let j = 0; j < sprites.length; j++) {
                // 충돌 여부 확인 하고 기록
                if (this.fires[i].collideWith(sprites[j])) {
                    sprites[j].isCollide = true;
                    this.fires[i].isCollide = true;

                    // 부딪힌 대상 위치에 아이템 생성
                    this.itemController.createItem(sprites[j].x);

                    break;
                }
            }
        }

        return isCollider;
    }

    Draw() {
        this.fires.forEach((fire) => fire.draw());
    }
}

 

불꽃은 위 클래스에 관리하고, 기본적으로는 오른쪽으로만 움직인다.

불꽃은 isCollide라는 변수를 가지고 있고, 해당 변수를 통해 충돌여부를 확인할 수 있다.

 

불꽃과 선인장이 부딪히면, 해당 자리에 아이템을 생성하고 불꽃과 선인장은 사라진다.

 

UpdateObject()
{
        if (this.cactiController.collideWithSingle(this.player)) {     
            Session.GetInstance().SendEvent(C2S_PACKET_TYPE_COLLIDE_CACTUS);                   
        }       

        if(this.itemController.collideWith(this.player)){
            Session.GetInstance().SendEvent(C2S_PACKET_TYPE_GET_ITEM);            
        }
}

 

플레이어가 선인장에 부딪히면 현재 스테이지에 비례하게 점수가 차감된다.

아이템과 부딪히면 점수가 증가한다.

 

🌙 하루를 마치며

1주일간 진행한 개인과제 주차가 끝났다.

10월 8일 오전 10시에 팀 프로젝트 발제가 있을 예정이다.

타워 디펜스( 유니티로 제공 )에 관한 서버를 만들 것이라는 공지를 전달 받았다.

 

이번에도 잘 참여해서 팀프로젝트를 완성할 수 있도록 노력해야겠다.

오늘의 목표

더보기

✔️ 프로그래머스 코테 문제 풀기

✔️ 개인 과제


⏱️ 오늘의 일정

프로그래머스 코테 문제 풀기

개인 과제


📜 프로그래머스 코테 문제 풀기

 

이진 변환 반복하기

https://github.com/YamSaeng/AlgorithmCodingTest/tree/main/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4/2/70129.%E2%80%85%EC%9D%B4%EC%A7%84%E2%80%85%EB%B3%80%ED%99%98%E2%80%85%EB%B0%98%EB%B3%B5%ED%95%98%EA%B8%B0

 

AlgorithmCodingTest/프로그래머스/2/70129. 이진 변환 반복하기 at main · YamSaeng/AlgorithmCodingTest

This is an auto push repository for Baekjoon Online Judge created with [BaekjoonHub](https://github.com/BaekjoonHub/BaekjoonHub). - YamSaeng/AlgorithmCodingTest

github.com

 

function solution(s) {
    var answer = [0, 0];

    while (s.length > 1) {
        answer[0]++;

        for (let i = 0; i < s.length; i++) {
            if (s[i] == '0') {
                answer[1]++;
            }
        }

        s = s.split("0").join("");

        let tempSArray = [];
        let tempsLength = s.length;

        let quotient = 0;
        let remain = 0;
        while (true) {
            quotient = Math.floor(tempsLength / 2);
            remain = tempsLength - quotient * 2;

            tempsLength = quotient;

            tempSArray.push(remain);

            if (quotient == 0) {
                break;
            }
        }

        s = tempSArray.reverse().join("");        
    }

    return answer;
}

 

문제 설명대로 구현하니 다행히도 쉽게 해결할 수 있었다.

 

📜 개인과제

 

개인과제를 진행했다.

 

https://dinorunner.com/ko/

 

크롬 다이노 게임 온라인

T-Rex Dinosaur (Dinosaur Google) - 인터넷이 없을 때 Chrome 브라우저에 숨겨진 게임의 복제본. 시작하려면 스페이스바를 누르십시오. 스페이스바 또는 위쪽 화살표와 아래쪽 화살표(↓)를 사용하여 공룡

dinorunner.com

 

 

앞서 언급한대로 크롬 다이노 게임에서 다른 움직임을 줬다.

우선은 좌, 우 화살표로 공룡을 직접 움직일 수 있도록 수정했다.

if (event.code === "ArrowLeft") {
    this.speed = -PLAYER_SPEED;
}

if (event.code === "ArrowRight") {
    this.speed = PLAYER_SPEED;
}

 

keydown 이벤트에서 왼쪽 화살표를 입력하면, -speed 값을 주고,

keydown 이벤트에서 오른쪽 화살표를 입력하면, speed 값을 줘서 공룡 캐릭터를 움직인다.

 

 

if (event.code === "KeyA") {
   if (this.fireAttackTimer <= 0 && this.fireCount > 0) {
        let game = Game.GetInstance();
        if (game != null) {
           this.fireCount--;
           game.jobQue.push(new Job(JOB_TYPE_CREATE_OBJECT_FIRE,
              OBJECT_TYPE_FIRE, this.x, this.y));

           this.fireAttackTimer = FIRE_ATTACK_TIMER;
        }
    }
}

 

A 키를 누르면 공룡 입에서 불꽃을 발사하도록 코드를 수정했다.

불꽃은 일정 개수를 가지고, R키를 눌러 재장전할 수 있다.

 

불꽃은 다가오는 선인장을 제거할 수 있다.

지금은 재장전할때, 바로바로 되는데 재장전시간을 둬서 선인장을 바로 없앨 수는 없도록 하긴 해야겠다.

 

https://github.com/YamSaeng/DinoRunner

 

GitHub - YamSaeng/DinoRunner

Contribute to YamSaeng/DinoRunner development by creating an account on GitHub.

github.com

 

오늘의 목표

더보기

✔️ 모의 면접

✔️ 개인 과제 


⏱️ 오늘의 일정

모의 면접개인 과제챌린지반 수업


📜 모의 면접

 

어제 언급한대로 오늘 모의 면접을 봤다.

총 3가지의 질문을 받았다.

 

1. IP의 개념과 주소체계, 서브넷에 관한 설명

2. 브라우저에 도메인을 입력하면 발생하는 일련의 과정 설명

3. 라우터, 라우팅과 라우팅 프로토콜 RIP, BGP의 대한 설명

 

면접 시간 전까지 암기를 하고 면접에 들어갔는데, 

그게 독이 된것 같다. 머리 속에 입력한 내용을 장황하게 설명하느라 튜터님이 강조한 '대화'를 하지 못했다.

피드백도 알고 있는 지식을 얘기한다기보다는 암기를 해서 설명하는 점이 강하고,

암기를 해서 설명하다보니 모든 지식을 끌어모아서 장황하게 설명하는 점이 좋지 않았다라고 피드백을 받았다.

 

면접은 '대화'라는 점을 강조 받았듯이 어떤 개념을 간단하게 설명을하고,

추가로 질문을 받으며 말 그대로 대화를 해 나가는 것이 중요하다라는 것을 깨달았다.

 

이번 모의 면접이 마지막은 아니고, 2번 정도 더 모의 면접 시간을 가질 것이라고 공지를 받았다.

다음 모의 면접에서는 위에서 받은 피드백 내용을 기억해두고 명심해서 임해야겠다.

 

 

📜 개인 과제

 

어제 제공 받은 스켈레톤 코드의 구조를 참고해서 다시 구성을 해야겠다.

 

https://github.com/YamSaeng/DinoRunner

 

GitHub - YamSaeng/DinoRunner

Contribute to YamSaeng/DinoRunner development by creating an account on GitHub.

github.com

 

📜 스탠다드반, 챌린지반 수업

 

스탠다드반에서 DNS 서버에 대해 배우고,

챌린지반에서는 데이터베이스 모델링에 관한 수업을 들었다.

오늘의 목표

더보기

✔️ 프로그래머스 코테 문제 풀이

✔️ 면접 특강

✔️ Node.js 게임서버 개발 강의 듣기


⏱️ 오늘의 일정

프로그래머스 코테 문제 풀이

면접 특강

Node.js 게임서버 개발 강의 듣기


📜 프로그래머스 코테 문제 풀이

 

피보나치 수

https://github.com/YamSaeng/AlgorithmCodingTest/tree/main/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4/2/12945.%E2%80%85%ED%94%BC%EB%B3%B4%EB%82%98%EC%B9%98%E2%80%85%EC%88%98

 

AlgorithmCodingTest/프로그래머스/2/12945. 피보나치 수 at main · YamSaeng/AlgorithmCodingTest

This is an auto push repository for Baekjoon Online Judge created with [BaekjoonHub](https://github.com/BaekjoonHub/BaekjoonHub). - YamSaeng/AlgorithmCodingTest

github.com

 

처음에 딱 보자마자 생각난 것이 재귀 함수라서, 바로 구현해봤다.

function Fibonacci(n) {
    if (n == 0) {
        return 0;
    }
    else if (n == 1) {
        return 1;
    }
    else {
        return (Fibonacci(n - 2) + Fibonacci(n - 1)) % 1234567;
    }
}

 

설렜던 기분과는 다르게.. 시간초과가 나는 바람에 다른 방법을 고민해봤다.

function solution(n) {      
    let answer = new Array(100001);
    
    answer[0] = 0;
    answer[1] = 1;

    for (let i = 2; i <= n; i++) {
        answer[i] = (answer[i - 2] + answer[i - 1]) % 1234567;
    }

    return answer[n];
}

 

미리 배열을 선언하고

[0] = 0

[1] = 1 

 

0과 1을 저장해두고 피보나치 공식에 맞게 배열을 채워나간후에, n번째 배열 값을 반환해준다.

 

 

📜 면접 특강

 

면접.. 면접에 대한 특강 시간을 가졌다. 

내일 16시에 모의 면접 시간이 30분간 잡혀있는데, 매우 많이 긴장된다.

면접에 나올 문제를 캠프에서 알려준게 있어서, 그 내용만큼은 암기하고 모의 면접 시간을 가져야겠다..

 

 

📜 Node.js 게임서버 개발 강의 듣기

 

Node.js 게임서버 개발 강의를 모두 수강했다.

이번 개인과제와 관련된 강의로

서버를 만들고, 클라를 만드는 강의다.

 

서버는 웹소켓을 이용해 만들고,클라는 

 

https://dinorunner.com/ko/

 

크롬 다이노 게임 온라인

T-Rex Dinosaur (Dinosaur Google) - 인터넷이 없을 때 Chrome 브라우저에 숨겨진 게임의 복제본. 시작하려면 스페이스바를 누르십시오. 스페이스바 또는 위쪽 화살표와 아래쪽 화살표(↓)를 사용하여 공룡

dinorunner.com

 

일명 크롬 다이노 게임이라고 불리는 게임코드를 제공받았다.

 

강의에서는 기본적인 틀을 제공해주고, 개인과제 조건에 맞게 서버와 클라를 다듬어 제출해야한다.

지금 드는 생각은 단조롭게 장애물을 점프해서 피하기보다는 좀 더 역동적인 움직임을 갖춰서 구현할 생각이다.

 

좀 더 자세한 내용은 내일 서버를 구현해보면서 생각해봐야겠다.

 

HTTP에 대해 알아야할 것

1. Request <-> Resonpse 구조 + 비연결성

  • 하나의 Request가 있으면 그에 대응하는 Response가 있다. 다시 말해,Request가 없으면 Response를 보내지 않는다.
  • 연결을 유지하지 않기 때문에 리소스를 줄일 수 있어서 많은 트래픽을 빠르게 처리가 가능하다.

 

2. Stateless ( 무상태 )

  • 연결을 한번 하고 끊기 때문에, 이전에 일어났던 일( 상태 )를 저장하고 있지 않는다.
  • 매번 새로운 요청을 처리한다. ( 세션, 쿠키, DB로 해당 요청에 대한 정보를 임의로 저장해 처리하긴 한다. )

3. HTTP 프로토콜의 메세지 구조

  • HTTP 프로토콜의 메세지 구조는 위 그림과 같다.
  • 이 중에서 중요하게 살펴볼 부분은 헤더( header ) 부분인데, 메세지에 필요한 모든 부가 정보가 들어있고, 그림처럼 넣고 싶은 내용을 임의로 추가 할 수도 있다.

 

General Header

  • Date : 현재 시간
  • Pragma : 캐시제어( no-cache ), HTTP/1.0에서 쓰던 것으로 HTTP/1.1에서는 Cache-Control이 쓰인다.
  • Cache-Control : 캐시 제어 + no-cache( 모든 캐시를 쓰기 전에 서버에 해당 캐시를 사용해도 되는지 확인 ) + public( 공유 캐시에 저장해도 됨 ) + max-age( 캐시의 유효시간을 명시 ) + private( '브라우저' 같은 특정 사용자 환경에만 저장 ) + must-revalidate( 만료된 캐시만 서버에 확인 ) + no-store( 캐시를 저장하지 않음 )
  • Transfer-Encoding : body 내용 자체 압축 방식 지정. 본문에 데이터 길이가 나와서 야금야금 브라우저가 해석해 화면에 뿌려줄 때 이 기능을 사용한다. ( 'chunked'면 본문의 내용이 동적으로 생성되어 길이를 모르기 때문에 나눠서 보낸다는 의미 )
  • Upgrade : 프로토콜 변경시 사용 
  • Via : 중계( 프록시 )서버의 이름, 버전, 호스트명
  • Content-Encoding : 본문의 리소스 압축 방식( transfer-encoding은 body 자체이므로 다르다 )
  • Content-type : 본문의 미디어 타입(MIME) 예) application/json, text/html
  • Content-Length : 본문의 길이
  • Content-Language : 본문을 이해하는데 가장 적절한 언어. 예) ko
  • Expires : 자원의 만료 일자
  • Allow : 사용이 가능한 HTTP 메소드 방식 예) GET, HEAD, POST ...
  • Last-Modified : 최근에 수정된 날짜
  • ETag : 캐시 업데이트 정보를 위한 임의의 식별 숫자
  • Connection : 클라이언트와 서버의 연결 방식 설정 HTTP/1.1은 kepp-alive로 연결을 유지하는게 디폴트

 

Request / Response Header

 ● request header form은 웹브라우저가 웹서버에 요청하는 것을 텍스트로 변환한 메세지들이다.

   ● Request Line : 어떤 웹서버로 접속( Host 부분 )해서, 어떠한 방식( HTTP / 1.1 )으로, 어떠한 메소드( GET )를 통해 무엇을( /doc/test/.html ) 요청했는지에 대한 메시지가 담겨있다. ( GET /test.html http 1.1 )

  ● Host : 요청하려는 서버 호스트 이름과 포트번호

  ● User-agent : 클라이언트 프로그램 정보 예) Mozilla / 4.0, Windows NT5.1 ( 이 정보를 통해 서버는 클라이언트 프로그램( 브라우저 )에 맞는 최적의 데이터를 보내줄 수 있다. )

  ● Referer : 바로 직전에 머물렀던 웹 링크 주소( 해당 요청을 할 수 있게된 페이지 )

  ● Accept : 클라이언트가 처리 가능한 미디어 타입 종류 나열 예) */* - 모든 타입 처리가능, application/json - json데이터 처리 가능

  ● Accept-charset : 클라이언트가 지원가능한 문자열 인코딩 방식

  ● Accept-language : 클라이언트가 지원가능한 언어 나열

  ● Accept-encoding : 클라이언트가 해석가능한 압축 방식 지정 예) gzip, deflate

  ● Content-location : 해당 개체의 실제 위치

  ● Content-disposition : 응답 메세지를 브라우저가 어떻게 처리할지 알려준다. 예) inline, attachment; filename='jeong-pro.xlsx'

  ● Content-Security-Policy : 다른 외부 파일을 불러오는 경우 차단할 리소스와 불러올 리소스 명시

      예) default-src 'self' -> 자기 도메인에서만 가져온다.

            default-src 'none' -> 외부파일은 가져올 수 없다.

            default-src https -> https로만 파일을 가져온다.

  ● If-Modified-Since : 여기에 쓰여진 시간 이후로 변경된 리소스를 취득. 페이지가 수정되었으면 최신 페이지로 교체하기 위해 사용된다.

  ● Authorization : 인증 토큰을 서버로 보낼 때 쓰이는 헤더

  ● Origin : 서버로 Post 요청을 보낼 때 요청이 어느 주소에서 시작되었는지 나타내는 값 ( 이 값으로 요청을 보낸 주소와 받는 주소가 다르면 CORS 에러가 난다. )

  ● Cookie : 쿠키 값 key-value로 표현된다. 예) attr1=value1; attr2=value2

 

● response header form은 웹브라우저가 요청한 메세지에 대해서 status 즉, 성공했는지 여부( 202, 400 등), 메세지, 그리고 요청한 응답 값들이 body에 담겨 있다.

  ● Location : 301, 302 상태코드일 때만 볼 수 있는 헤더로 서버의 응답이 다른 곳에 있다고 알려주면서 해당 위치( URL )를 지정한다.

  ● Server : 웹서버의 종류 예) nginx

  ● Age : max-age 시간내에서 얼마나 흘렀는지 초 단위로 알려주는 값

  ● Referrer-policy : 서버 referrer 정책을 알려주는 값 예) origin, no-referrer, unsafe-url

  ● WWW-Authenticate : 사용자 인증이 필요한 자원을 요구할 시, 서버가 제공하는 인증 방식

  ● Proxy-Authenticate : 요청한 서버가 프록시 서버인 경우 유저 인증을 위한 값

  ● 응답 상태 코드 ( 200, 202, 404 등 )

 

HTPP는 Application Layer 에서 동작하는 프로토콜이고, transport laye( 전송계층 )의 위에서 동작한다.

전송계층의 대표적인 프로토콜은 TCP / UDP가 있다.

HTTP는 TCP와 UDP 둘 중 하나의 연결을 통해서 동작한다. ( 결론적으로 TCP / UDP 프로토콜이 없으면 동작 불가 )

 

예외)

HTTP / 2 : 멀티플렉싱 기술의 등장으로 한번의 연결을 재사용하는 것이 가능하다.

HTTP / 3 : QUIC( UDP )위에서 동작한다.

 

TCP

HTTP는 비연결성이지만 TCP는 연결지향성이다.

  • TCP는 데이터교환을 할 때 무조건 연결을 가진다.
  • HTTP의 Req <-> Res가 발생할 때 밑에서 TCP 연결이 이루어진다.
  • TCP는 3-handshake라고 하는 연결 과정을 가진다.

 

TCP 통신방법

 양방향 통신( Full-Duplex ) 순서

  1. 서버는 접속 요청을 받기 위한 소켓을 연다. ( Listen )
  2. 클라이언트는 소켓을 만들고, 서버에 접속을 요청한다. ( Connect )
  3. 서버는 접속 요청을 받아서 클라이언트와 통신할 소켓을 따로 만든다. ( Accept )
  4. 소켓을 통해 서로 데이터를 주고 받는다. ( Send & Receive 반복 )
  5. 통신을 마치면 소켓을 닫는다. ( Close ( 상대방은 Receive로 인지할 수 있다. ) )

 

웹소켓( Websocket )

 

HTTP 프로토콜 위에서 동작하는 실시간 양방향 통신( Full-Duplex )

특징

 1. 실시간 통신

  • 웹소켓은 연결이 활성화된 상태에서 빠르고 지속적인 메세지 교환을 허용한다. 이로 인해 에플리케이션은 사용자에게 지연 없는 인터랙션을 제공할 수 있다.

 2. 양방향 통신( Full-Duplex )

  • 클라이언트와 서버가 동시에 서로에게 베세지를 보낼 수 있다. 이는 한 쪽이 다른 쪽의 메세지를 기다리지 않고도 독립적으로 메세지를 송수신 할 수 있음을 의미한다.

 3. 지속적 연결

  • 웹소켓 연결이 수립되면, 그 연결은 클라이언트나 서버가 명시적으로 종료할 때까지 유지된다. 이는 오버헤드를 줄이고 빠른 데이터 전송을 가능하게 한다.

 4. 낮은 오버헤드

  • 웹소켓은 데이터 패킷의 헤더가 매우 작기 때문에 오버헤드가 낮다. 이는 효율적인 네트워크 자원 사용을 가능하게 한다.

 5. HTTP와의 호환성

  • 웹소켓은 HTTP 포트( 80과 443 )을 통해 작동하기 때문에 기존 웹 인프라와 잘 통합된다. 웹소켓 연결은 HTTP 연결을 통해 초기화되며, 이후 전이중 통신 채널로 전환된다.

 

각 프토토콜의 헤더 비교

HTTP 헤더

GET /data HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/90.0.4430.212
Accept: application/json
Cookie: sessionToken=abcdef; userID=12345
  • 보통의 HTTP Request Header의 일부분 ( 여기에 더해 General Header까지 추가하면 대략 수백 바이트의 양을 가진다. )

 

웹소켓 헤더

  0x81 0x05
  • 연결 이후 데이터 교환할때의 websocket의 헤더
  • 극도로 간소화되어 있지만, FIN 비트, Opcode, Mask 비트, Payload 길이 정보가 포함되어 있다.

 

TCP 패킷 헤더 

  Source Port:       54321
  Destination Port:  80
  Sequence Number:   123456789
  Acknowledgment Number: 987654321
  Data Offset:       5 (Header Length: 20 bytes)
  Reserved:          0
  Flags:             [ACK, PSH]
  Window Size:       65535
  Checksum:          0x1a2b
  Urgent Pointer:    0
  Options:           [No options]
  Payload Data:      "Hello, TCP!"

 

TCP 패킷의 구조

TCP 패킷, 종종 세그먼트라고 불리는 것은 다음과 같은 주요 부분으로 구성된다.

  1. 소스 포트번호( 16비트 ) : 발신자의 포트 번호
  2. 목적지 포트번호( 16비트 ) : 수신자의 포트 번호
  3. 시퀀스 번호( 32비트 ) : 데이터 스트림 내에서 이 세그먼트의 위치를 식별하기 위한 번호
  4. 응답 번호( 32비트 ) : 다음에 기대하는 데이터의 시퀀스 번호
  5. 헤더 길이( 4비트 ) : 헤더의 크기를 나타냄
  6. 예약된( 3비트 ) : 향후 사용을 위해 예약된 공간
  7. 플래그( 9비트 ) : 연결 설정, 관리, 종료를 제어하는 다양한 플래그
  8. 윈도우 크기( 16비트 ) : 수신자가 받을 준비가 되어 있는 버퍼의 크기
  9. 체크섬( 16비트 ) : 오류 검사를 위한 값
  10. 긴급 데이터 포인터( 16비트 ) : 긴급 데이터의 끝을 가리키는 포인터
  11. 옵션( 가변 길이 ) : 필요에 따라 추가적인 옵션을 포함할 수 있음
  12. 데이터( 가변 길이 ) : 실제 전송할 데이터

 

웹소켓의 연결방법은 TCP의 연결방법 ( 3-way-handshake)를 닮아있다.

웹소켓은 기본적으로 TCP 연결 위에서 작동하기 때문에, 웹소켓 연결을 시작하기 전에 TCP의 표준 연결 방법인 3-way handshake가 수행된다. 하지만 웹소켓은 이후에 추가적인 핸드셰이크 과정을 진행해 웹소켓 특유의 연결을 완성한다.

 

 

테스팅 프레임워크 Jest에 대해 알아보기

Node.js를 통해 사용하고 있는 언어인 JavaScript에서 사용이 가능한 테스팅 프레임워크의 종류는 매우 다양하다.

이 중 Jest를 사용해보자.

 

Jest는 다른 테스팅 프레임워크와 비교하면 여러가지 장점이 있지만, 그 중 가장 제일이라고 생각되는 것은 테스트 코드의 표현이 다른 프레임워크보다 훨씬 간결하다.

 

jest 모듈 설치

# yarn 프로젝트를 초기화합니다.
yarn init -y

# DevDependencies로 jest를 설치합니다.
yarn add -D jest

 

 

계층형 아키텍처 패턴 프로젝트 - 템플릿

https://hanghae99-node-example.s3.ap-northeast-2.amazonaws.com/re/layered-architecture-pattern-template.zip

 

위 링크에서 파일을 다운로드 받아 압축을 해제한다.

 

  • .env 파일에서 DB 속성을 변경한다.

꼭, DATABASE_URL을 대여한 RDS의 속성값으로 수정한다.

사용할 데이터베이스 명은 layerd_architecture_pattern_db 로 한다.

 

// .env

# MySQL의 데이터베이스 URL입니다.
DATABASE_URL="mysql://아이디:비번@RDS_EndPoint/layered_architecture_pattern_db"

 

yarn 패키지를 설치하고, Prisma로 DB 및 테이블 정보를 동기화 한다.

 

# yarn 패키지 설치
yarn

# Prisma를 이용하여 DB 및 테이블 생성
npx prisma db push

 

계층형 아키텍처 패턴 프로젝트 ( 디렉토리 구조 )

내 프로젝트 폴더 이름
├── package.json
├── prisma
│   └── schema.prisma
├── src
│   ├── app.js
│   ├── controllers
│   │   └── posts.controller.js
│   ├── middlewares
│   │   ├── error-handling.middleware.js
│   │   └── log.middleware.js
│   ├── repositories
│   │   └── posts.repository.js
│   ├── routes
│   │   ├── index.js
│   │   └── posts.router.js
│   ├── services
│   │   └── posts.service.js
│   └── utils
│       └── prisma
│           └── index.js
└── yarn.lock

 

이 프로젝트의 디렉토리 구조는 기존 프로젝트와는 조금 다르다.

새롭게 controllers, services, repositories 라는 폴더가 보이는데, 이 폴더들은 각 계층병 역할을 담당한다.

 

새로운 디렉토리 구조에 맞춰 3계층 아키텍처 프로젝트를 구성해보자.


 

컨트롤러( Controller )

프레젠테이션 계층( Presentation Layer ) 

3계층 아키텍처 패턴에서 가장 먼저 클라이언트의 요청( Request )을 만나게 되는 계층이고, 대표적으로 컨트롤러( Controller )가 이 역할을 담당한다.

  • 하위 계층( 서비스 계층, 저장소 계층 )에서 발생하는 예외( Exception )를 처리한다.
  • 클라이언트가 전달한 데이터에 대해 유효성을 검증하는 기능을 수행한다.
  • 클라이언트의 요청을 처리한 후 서버에서 처리된 결과를 반환( Response )한다.

 

컨트롤러( Controller )

클라이언트의 요청( Request )을 처리하고, 서버에서 처리된 결과를 반환( Response )하는 역할을 담당한다.

컨트롤러( Controller )는 추가적으로 아래의 역할을 담당한다.

  • 클라이언트의 요청( Request )을 수신한다.
  • 요청( Request )에 들어온 데이터 및 내용을 검증한다.
  • 서버에서 수행된 결과를 클라이언트에게 반환( Response )한다.

 

Express로 구현하는 컨트롤러

 

Express에서는 컨트롤러라우터( Router )를 연결하기 위해서는 express.Router를 사용해, 라우터가 클라이언트의 요청( Request )에서 특정 URIHTTP Method를 전달받았을 때 컨트롤러의 특정 메서드로 요청된 내용을 전달하도록 구현해야한다.

 

그렇기 때문에 routes 폴더에서 posts.router.js 라는 파일을 만들어 PostsController와 연결하도록 구성해보자.

 

routes/posts.router.js

// src/routes/posts.router.js

import express from 'express';
import { PostsController } from '../controllers/posts.controller.js';

const router = express.Router();

// PostsController의 인스턴스를 생성합니다.
const postsController = new PostsController();

/** 게시글 조회 API **/
router.get('/', postsController.getPosts);
/** 게시글 작성 API **/
router.post('/', postsController.createPost);

export default router;

 

router.get('/', postsContoller.getPosts); 

  • router.get은 저희가 Express를 이용해 API를 만들때 매번 사용했던 코드다.
  • 이 메서드는 / URI에 대한 GET 메서드 요청이 들어올 경우, postsController.getPosts를 호출하라는 의미다.
  • 즉, 클라이언트의 요청이 들어오면, PostsController 클래스에서 정의된 getPosts메서드를 실행하도록 라우터를 설정한 것이다.

위 결과로 Post에 해당하는 컨트롤러와 라우터를 연결할 수 있게 되었다.

 

posts.router.js 파일을 통해 컨트롤러라우터연결했으니, 다음 단계로 posts.controller.js 파일을 작성해 Post컨트롤러를 구현해보자.

 

controllers/posts.controller.js

// src/controllers/posts.controller.js

import { PostsService } from '../services/posts.service.js';

// Post의 컨트롤러(Controller)역할을 하는 클래스
export class PostsController {
  postsService = new PostsService(); // Post 서비스를 클래스를 컨트롤러 클래스의 멤버 변수로 할당합니다.

  getPosts = async (req, res, next) => {
    try {
      // 서비스 계층에 구현된 findAllPosts 로직을 실행합니다.
      const posts = await this.postsService.findAllPosts();

      return res.status(200).json({ data: posts });
    } catch (err) {
      next(err);
    }
  };

  createPost = async (req, res, next) => {
    try {
      const { nickname, password, title, content } = req.body;

      // 서비스 계층에 구현된 createPost 로직을 실행합니다.
      const createdPost = await this.postsService.createPost(
        nickname,
        password,
        title,
        content,
      );

      return res.status(201).json({ data: createdPost });
    } catch (err) {
      next(err);
    }
  };
}

 

await this.postsService.findAllPosts();

  • await this.postsService.findAllPosts(); 는 PostsController 클래스의 postService 인스턴스에서 findAllPost 메서드를 호출한다.
  • 컨트롤러는 하위 계층내부 구조에 대해 신경쓰지 않는다. 대신, 외부에 공개된 메서드를 호출하기만 한다. 이것이 가능한 이유는 추상화( Absctraction )의 특성 덕분이다.
  • PostsController 클래스는 전달된 요청( Request )을 처리하기 위해 PostsService를 호출하도록 구현했다. 여기서 컨트롤러비즈니스 로직을 직접 수행하지 않고, 클라이언트요청서비스 계층으로 바로 전달 하도록 구현한 것을 확인 할 수 있다.

결국, PostsController 클래스클라이언트의 요청( Request )서비스 계층으로 전달하는 역할을 수행하며, 서비스 계층이 어떠한 내부 구조를 통해 비즈니스 로직을 수행하는지는 상위 계층컨트롤러에게는 중요하지 않다.

 


 

서비스( Service )

서비스 계층( Service Layer )

다른 이름으로는 비즈니스 로직 계층( Business logic layer )은 아키텍처의 가장 핵심적인 비즈니스 로직을 수행하고 클라이언트가 원하는 요구사항을 구현하는 계층이다.

  • 프레젠테이션 계층( Persentation Layer )데이터 엑세스 계층( Data Access Layer ) 사이에서 중간 다리 역할을 하고, 서로 다른 두 계층이 직접 통신하지 않게 만들어 준다.
  • 서비스( Service )데이터가 필요할 때, 저장소( Repository )에게 데이터를 요청한다.
  • 어플리케이션의 규모가 커질수록, 서비스 계층의 역할코드의 복잡성도 점점 더 커지게 된다.
  • 어플리케이션의 핵심적인 비즈니스 로직을 수행하고, 클라이언트들의 요구사항을 반영해 원하는 결과를 반환해주는 계층이다.

 

서비스 계층의 장단점

서비스 계층의 장점

  • 사용자의 유즈 케이스( Use Case )워크플로우( Workflow )를 명확히 정의하고 이해할 수 있도록 도와준다.
  • 비즈니스 로직이 API 뒤에 숨겨져 있으므로, 서비스 계층의 코드를 자유롭게 수정하거나 리팩터링할 수 있다.
  • 저장소 패턴( Repository Pattern )가짜 저장소( Fake Repository )와 조합하면 높은 수준테스트작성할 수 있다.

서비스 계층의 단점

  • 서비스 계층 또한 다른 추상화 계층이므로, 잘못 사용하면 코드의 복잡성을 증가시킬 수 있다.
  • 한 서비스 계층이 다른 서비스 계층에 의존하는 경우, 의존성 관리가 복잡해질 수 있다.
  • 서비스 계층에 너무 많은 기능을 넣으면 빈약한 도메인 모델( Anemic Domain Model )과 같은 안티 패턴이 생길 수 있다.

 

Express로 구현하는 서비스 계층

Service

  • 사용자의 요구사항을 처리하는 핵심 부분
  • DB 정보가 필요할 때는 Repository에게 요청한다.

PostsController 클래스가 클라이언트의 요청( Request )을 PostsServer 클래스에게 전달하는 과정을 살펴봤다.

이번에는 서비스 계층( Service Layer )에게 비즈니스 로직을 어떻게 수행하고, 필요한 데이터를 어떻게 저장소( Repository )로부터 요청하는지 확인해보도록 하자.

 

posts.service.js

// src/services/posts.service.js

import { PostsRepository } from '../repositories/posts.repository.js';

export class PostsService {
  postsRepository = new PostsRepository();

  findAllPosts = async () => {
    // 저장소(Repository)에게 데이터를 요청합니다.
    const posts = await this.postsRepository.findAllPosts();

    // 호출한 Post들을 가장 최신 게시글 부터 정렬합니다.
    posts.sort((a, b) => {
      return b.createdAt - a.createdAt;
    });

    // 비즈니스 로직을 수행한 후 사용자에게 보여줄 데이터를 가공합니다.
    return posts.map((post) => {
      return {
        postId: post.postId,
        nickname: post.nickname,
        title: post.title,
        createdAt: post.createdAt,
        updatedAt: post.updatedAt,
      };
    });
  };

  createPost = async (nickname, password, title, content) => {
    // 저장소(Repository)에게 데이터를 요청합니다.
    const createdPost = await this.postsRepository.createPost(
      nickname,
      password,
      title,
      content,
    );

    // 비즈니스 로직을 수행한 후 사용자에게 보여줄 데이터를 가공합니다.
    return {
      postId: createdPost.postId,
      nickname: createdPost.nickname,
      title: createdPost.title,
      content: createdPost.content,
      createdAt: createdPost.createdAt,
      updatedAt: createdPost.updatedAt,
    };
  };
}

 

이번 서비스 계층( Service Layer )에서 PostsService 클래스가 PostsRepository의 findAllPosts, createPost 메서드를 호출하는 것을 확인할 수 있다. 해당 코드는 서비스가 비즈니스 로직을 수행하는 데 필요한 데이터를 저장소 계층( Repository Layer )에게 요청해 가져오는 것을 확인 할 수 있다.

또한, 서비스 계층에서는 return posts.map(post => {}); 와 같이 데이터를 가공하는 작업이 이루어진다.

만약, 저장소 계층에서 받은 데이터를 그대로 클라이언트에게 전달한다면, 사용자의 비밀번호와 같은 민감한 정보까지 노출되는 보안 문제가 발생해, 서버의 보안성이 떨어지는 결과를 낳는다.

 


 

저장소( Repository )

저장소 계층( Repository Layer )

데이터 엑세스 계층( Data Access Layer )이라고 불린다. 주로 데이터베이스와 관련된 작업을 처리하는 계층이다.

  • 데이터 접근과 관련된 세부 사항을 숨기는 동시에, 메모리상에 데이터가 존재하는 것처럼 가정해 코드를 구현한다.
  • 저장소 계층을 도입하면, 데이터 저장 방법을 더욱 쉽게 변경할 수 있고, 테스트 코드 작성시 가짜 저장소( Mock Repository )를 제공하기가 더 쉬워진다.
  • 어플리케이션의 다른 계층들은 저장소의 세부 구현 방식에 대해 알지 못하더라도 해당 기능을 사용할 수 있다. 즉, 저장소 계층의 변경 사항이 다른 계층에 영향을 주지 않는 것이다. ( 객체 지향의 개념 중 추상화( Abstraction)와 관계가 있다. )
  • 저장소 계층은 데이터 저장소를 간단히 추상화한 것으로, 이 계층을 통해 모델 계층과 데이터 계층을 명확하게 분리할 수 있다.

대표적인 저장소 계층의 메서드

  • add(), create() : 새 원소를 저장소에 추가한다.
  • get(), find() : 이전에 추가한 원소를 저장소에 가져온다.

 

저장소 계층의 장단점

 

저장소 계층의 장점

  • 데이터 모델과 데이터 처리 인프라에 대한 사항을 분리했기 때문에 단위 테스트( Unit test )를 위한 가짜 저장소( Mock Repository )를 쉽게 만들 수 있다.
  • 도메인 모델을 미리 작성해, 처리해야할 비즈니스 문제에 더 잘 집중할 수 있다.
  • 객체를 테이블에 매칭하는 과정을 원하는 대로 제어할 수 있어서 DB 스키마를 단순화할 수 있다.
  • 저장소 계층에 ORM을 사용하면 필요할 때 MySQL과 Postgre와 같은 다른 데이터베이스로 쉽게 전환할 수 있다.

저장소 계층의 단점

  • 저장소 계층이 없더라도 ORM은 모델과 저장소의 결합도를 충분히 완화시켜 줄 수 있다. ( ORM이 없을 때 대부분의 코드는 Raw Query로 작성되어 있기 때문 )
  • ORM 매핑을 수동으로 하려면 개발 코스트가 더욱 소모된다. ( 여기서 설명하는 ORM은 이전에 사용한 Prisma와 같은 라이브러리를 말한다. )

 

Express로 구현하는 저장소 계층

Repository

  • 데이터베이스 관리( 연결, 해제, 자원 관리 ) 역할을 담당한다.
  • 데이터베이스의 CRUD 작업을 처리한다.

3계층 아키텍처의 마지막 계층인 저장소 계층( Repository Layer )이다.

이전에 작성했던 코드에서 서비스 계층( Service Layer )인 PostsServices에서 PostsRepository를 호출해 데이터를 요청하는 것을 확인할 수 있었다.

이번에는 저장소 계층( Repository Layer )이 어떻게 데이터베이스의 데이터를 가져와 상위 계층에게 반환하는지 확인해보도자.

 

posts.repository.js

// src/repositories/posts.repository.js

import { prisma } from '../utils/prisma/index.js';

export class PostsRepository {
  findAllPosts = async () => {
    // ORM인 Prisma에서 Posts 모델의 findMany 메서드를 사용해 데이터를 요청합니다.
    const posts = await prisma.posts.findMany();

    return posts;
  };

  createPost = async (nickname, password, title, content) => {
    // ORM인 Prisma에서 Posts 모델의 create 메서드를 사용해 데이터를 요청합니다.
    const createdPost = await prisma.posts.create({
      data: {
        nickname,
        password,
        title,
        content,
      },
    });

    return createdPost;
  };
}

 

이번 저장소 계층( Repository Layer )에서는 PostRepository 클래스에서 Prisma의 메소드를 사용해 데이터를 조회하거나 생성하는 것이 가장 핵심적인 내용이다.

 

위 예제에서는 단일 테이블만 활용해 Prisma를 사용했기 때문에 코드가 복잡해지지 않았다. 당연히 어플리케이션의 규모가 커지거나, 데이터베이스의 구성이 복잡해지면 저장소 계층의 구조 또한 복잡해진다.

오늘의 목표

더보기

✔️ 프로그래머스 코테 문제 풀기

✔️ 챌린지반 수업 참가

✔️ Node.js 심화 강의 듣기


⏱️ 오늘의 일정

프로그래머스 코테 문제 풀기
Node.js 심화 강의 듣기

챌린지반 수업 참가 


📜 프로그래머스 코테 문제 풀기

 

햄버거 만들기

https://github.com/YamSaeng/AlgorithmCodingTest/tree/main/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4/1/133502.%E2%80%85%ED%96%84%EB%B2%84%EA%B1%B0%E2%80%85%EB%A7%8C%EB%93%A4%EA%B8%B0

 

AlgorithmCodingTest/프로그래머스/1/133502. 햄버거 만들기 at main · YamSaeng/AlgorithmCodingTest

This is an auto push repository for Baekjoon Online Judge created with [BaekjoonHub](https://github.com/BaekjoonHub/BaekjoonHub). - YamSaeng/AlgorithmCodingTest

github.com

 

function solution(ingredient) {
    var answer = 0;

    let ingredients = [];

    for (let i = 0; i < ingredient.length; i++) {
        ingredients.push(ingredient[i]);

        if (ingredients.length >= 4
            && ingredients[ingredients.length - 1] == 1
            && ingredients[ingredients.length - 2] == 3
            && ingredients[ingredients.length - 3] == 2
            && ingredients[ingredients.length - 4] == 1) {

            answer++;
            ingredients.pop(); // 1
            ingredients.pop(); // 3
            ingredients.pop(); // 2
            ingredients.pop(); // 1
        }
    }

    return answer;
}

 

 

📜 Node.js 심화 강의 듣기

 

캠프에서 제공받은 Node.js 심화 강의를 수강하고 있다.

앞서 언급한 대로 Node.js의 심화 내용이라기보다는

객체지향 프로그래밍과 아키텍처 패턴을 자세히 알아보는 수업이다.

 

2024.09.27 - [IT] - [IT] 객체 지향 설계 5 원칙 ( SOLID )

 

[IT] 객체 지향 설계 5 원칙 ( SOLID )

객체 지향 프로그래밍 및 설계의 다섯 가지 핵심 원칙을 SOLID라고 부른다.SOLID는 객체 지향 프로그래밍 및 설계의 다섯 가지 기본 원칙의 맨 앞단어를 하나씩 가져와 만든 것이다.SOLID 원칙을 따

program-yam.tistory.com

 

2024.09.27 - [IT] - [IT] 아키텍처 패턴 ( Architecture Pattern )

 

[IT] 아키텍처 패턴 ( Architecture Pattern )

아키텍처 패턴은 소프트웨어의 구조를 구성하기위한 가장 기본적인 토대를 제시한다.아키텍처 패턴은 각각의 시스템들과 그 역할이 정의되어 있고, 여러 시스템 사이의 관계와 규칙 등이 포함

program-yam.tistory.com

 

2024.09.27 - [IT] - [IT] 계층형 아키텍처 패턴 ( Layered Architecture Pattern )

 

[IT] 계층형 아키텍처 패턴 ( Layered Architecture Pattern )

계층형 아키텍처 패턴 ( Layered Architecture Pattern )은 시스템을 여러 계층으로 분리하여 관리하는 아키텍처 패턴이다.현재 가장 널리 채택되고 있는 아키텍처 패턴 중 하나다. ( Spring, Nest.js을 사용

program-yam.tistory.com

 

객체 지향 설계 원칙 ( SOLID )와 아키텍처 패턴, 계층형 아키텍처 패턴에 대해서 배웠다.

 

📜 챌린지반 수업 듣기

 

이번 수업도 DB에 대한 내용을 배웠다.

트랜잭션의 대한 개념과, ACID 특성, 데이터베이스 보안 ( 인증, 인가 )에 대한 내용을 배웠다.

오늘의 목표

더보기

✔️ 새로운 팀 편성

✔️ 개인과제 발제

✔️ Node.js 심화 주차 수업 듣기


⏱️ 오늘의 일정

  • 개인 과제 발제
  • 새로운 팀 노션 작성
  • Node.js 심화 주차 수업 듣기

📜 개인 과제 발제

 

개인 과제 발제 시간이 있어서 참가했다.

이번 주차는 심화 숙련 주차로, 드디어 웹 소켓을 활용해 TCP로 통신하는 게임을 만드는 개인과제를 만들고,

그다음에 팀 프로젝트를 수행하는 주차라고 공지를 받았다.

 

10월 7일까지 캠프에서 제시한 과제를 수행해야하는데,

 

클라는 위 게임을 강의를 보면서 직접 구현해보고, 이에 대응하는 서버는 직접 짜는 방식이라고 설명을 받았다.

드디어 TCP로 작동하는 게임 주차가 시작되긴 했는데, Node.js 에서는 소켓 프로그래밍을 어떻게 구현할지 기대가 된다.

 

팀 프로젝트는 간단히 소개만 받았는데, 타워 디펜스라는 게임을 만들거라고 들었다.

 

📜 새로운 팀 편성

 

새로운 주차에 진입하면서 앞서 언급한대로 새로운 팀에 편성되었다.

총 6명이 배정되었는데, 한분이 입문숙련으로 빠져서, 5명이 되었다. 

아마도.. 중간에 한명이 들어올수도...?

 

 

📜 Node.js 심화 수업 듣기

새로운 주차에 진입하면서 강의도 새로 제공 받았다.

강의는 총 3가지로,

 Node.js 심화, 게임서버 개발, 컴퓨터 CS 수업으로 구성된다.

 

Node.js 심화부터 들을 생각인데, 내용을 살펴보니 주로 객체 프로그래밍에 대한 내용이였다.

지겹게 들은 객체 프로그래밍이지만, 이번에 한번더 강의를 들으면서 정리를 또 해야겠다.

 

2024.09.26 - [IT] - [IT] 객체 지향 프로그래밍 ( Object-Oriented Programming, OOP )

 

[IT] 객체 지향 프로그래밍 ( Object-Oriented Programming, OOP )

객체 지향 ( Object - Oriented )객체 ( Object )는 현실 세계의 물체나 개념을 소프트웨어 세계로 옮긴 것이다.예를 들면, '자동차'나 '사람'처럼 생각하면 된다. 여기서, 객체는 여러 속성과 행동(메서드

program-yam.tistory.com

 

 

 

+ Recent posts