아무래도, 과제 기간엔 과제 외에 뭘 하기가 힘들어서 ! 

TIL 도  온통 과제의 내용이 되어버린다 !

 

 

 

우선, 리팩토링 하고싶은 코드 몇개를 살펴보자.

기존 코드 

 

 

가차 ...또 너야?

 

문제의 원인은

return 하는 메세지에, 랜덤으로 획득한 선수 Name 을 출력하고 싶어서 이다.

 

첫번째 장애물은 createMany 

사용법이 난해해서, 깔끔하게 [{data1,data2 }] 배열로 전달하지 않으면 사용하기가 어렵다.

 

두번째 장애물은 Math.random

랜덤 뽑기의 대상이 된 playerId 와 playerName을 정상적으로 가져와야한다. 

 

세번째 장애물은 accountId 

가차 뽑기의 결과물을 소유하게될 accountId 는 당연히 모든 선수목록 table 에는 없다

 

 

슬프게도, createMany의 반환 결과는 create 로 만들어낸 숫자이기 때문에

거기서 떼 올 수 없다는것

 

 

결국, 가차 과정에서 playerId, playerName, accountId 를 전부 가지고 나온 다음에

 용도에 맞게 다시 쪼개기로 했다.

 

 

 

예시라고 나오는게 이런것 밖에 없어서....

createMany를 원하는대로 사용하기가 어렵다

 

 

 

 

 

map 을 2번 사용해서 각각 쪼개야 하지만, 나름 목적을 달성했고

그렇게 큰 리스크도 아니기에 이렇게 사용하기로 했다.

으음 !

 

문제 2

 

내 수준에서 적당히 기분이 안좋은 코드

 

 

myTeamSearch 라는 동일한 값을 여러번 체크하는데다가 이득도 별로 없는 코드

 

 

일단 가져올 때는 전부 true 로 가져오도록 하자 .

 

 

그래서 일단 map으로 정렬을 하되, 

myTeamSearch 를 여기서 한번 체크해서 false인 경우 일부 결과를 다시 뺏어가버리면 된다 !!

 

 

기능이 잘 작동하는 모습!!!

 

 

 

 

오늘은 !  진행중인 브라우저 구현 부분에 대한 TIL 을 작성해보자.

 

사실, 프론트는 이번 과제의 목표도 아니고 !!

필수도, 도전도 아닌 선택의 영역이다.

 

하지만, 우리팀은 프론트를 진행하는 것으로 결정이 됐기 때문에,

백엔드, API가 어느정도 완성돼가는 인원부터 브라우저를 구현하도록 했다.

 

 

현재, 목표로 했던 팀=> 선수관리 API 관련한 부분은 대부분 브라우저에서 작동하도록 구현했다.

 

구현하고 싶으나 시간도, 방법도 모르겠는

오류 처리 방식, message 출력,  특정 div 영역 새로고침, API 에 맞춤형 Request 창 등등

아직 해야할것이 많지만, 백엔드가 완벽한 것이 아니기 때문에 이쯤에서 다시 백엔드로 돌아가기로 했다.

 

먼저, 어제 고민했던 중복선수 카운트 부분이다.

 

 

로우쿼리.. 돌아왔구나..

 

기존에 사용했던 Prisma 의 distinct는 count 를 하는데 어려움이 있다.

그래서 prisma의 group by 를 사용하려고 했으나, join과 그룹화, 카운트를 동시에 진행하는것이 굉장히 난해했다.

 

오히려 쿼리문을 사용한다면 쉬울것 같은데? 라는 생각에서 작성을 해 보았다.

 

한번에 해결될 리가 없다 

 

count 를 한 결과값이 5n...  아마도, bigint 의 형식으로 출력되는듯 하다.

아무래도, 얼마나 될지 모르는 양의 데이터를 count 하는것이기 때문에

기본적으로 mysql에서는 bigint를 출력하게 되어있는듯 하다. 

 

bigint 는 json 형태로 값을 전달할 수 없는것인지, 에러가 발생한다.

::int  CAST() 등등 으로 제발int를 출력하도록 유도했지만, 계속해서 에러만 발생했다.

 

게다가  boolean 값이어야 할 isPicked 컬럼은 아예 정수로 반환이 되었다.

 

어차피, player능력치에 해당하는 부분은 강화수치를 적용하기 위해 재가공을 해야하는 만큼,

한번에 map으로 재가공을 하기로 했다.

 

 

수량에는 parseInt를, isPicked 에는 Boolean() 을, 능력치 부분에는 강화수치를 적용하는 것으로 처리했다.

 

 

 api 자체는 선수의 조회기능이기 때문에, 능력치를 가독성 있게 문자열로 표현하게했다.

 

결과는 그럴싸 하지만, 탐탁치는 않은 부분이다 !!

보유한선수를 모두 조회하고, 꽤 많은 데이터를 map을 통해 재가공 하기 때문에 리소스 소모가 클 수 밖에 없다.

 

당장 최적화 방법이 떠오르지 않고, 추후 브라우저의 보유선수 조회 기능에서 많은 기능이 연계될 것으로 계획했기 때문에

일단은 이 상태로 진행하기로 했다.

 

사실, 이미 어느정도는 작동한다

 

 

하나 하나 쌓여가는 API 들 

 

다음 목표는 트랜잭션과 오류 처리 부분이다 !

 

 

 

 

하루가 끝나가고, TIL 을 쓸 무렵 중대한 오류가 발견되었다...

무려 작성한 스키마 내용중, 

playerDefense 부분만  P !!!

대문자로 시작하는 것이었다.

(암튼 내가한것은 아님)

 

저 대문자 P 를 p로 고치는것만 해도 db push를 새로 해야하며, 

그렇게 되면 데이터가 모두 날라간다는 경고문이 출력된다.

 

현재, 데이터베이스에 존재하는 데이터들은 어디까지나 임시 수준이기 때문에 

일단은 데이터를 초기화하고 진행하는것으로 결정이 되었다.

크헉

 

다음으로는, 개선이 필요한 부분 !

 

어떻게 보면 위의 사건으로 인해 발견된 문제점인데,  어제와 동일한 부분인 

랜덤 뽑기 부분이다.

 

 

만약, 선수 데이터 테이블이 위처럼만 구성이 되어있다면?

모종의 이유로 중간중간 playerId에 구멍이 나있다면?

 

기존의 랜덤 추출 방식이 적용된다면, 최대값인 7 기준으로 1~7의 숫자를 뽑을 것이다.

 

그렇다면, 1 ,2 ,3 이 뽑혔을 경우 에러가 발생하게 된다.

 

위와 같은 사건(?) 이 발생하거나, 

의도적으로 몇몇 선수 데이터를 제거했을 때에도, 유효한 가차뽑기를 만들어야한다.

 

우선, 모든 선수를 조회해서 playerId를 추출해서 배열 형태로 만든다 !

 

알고리즘 풀이 시간인가?

이제 기존처럼 반복문으로 json 형태로 데이터를 가공해야하는데, 

randomPlayer 의 범위를, 위에서 구한 allPlayers 배열의 인덱스 범위로 만들면 된다 .

 

그렇게 해당 인덱스의 playerId 를 넣어주면 완성 !!

 

 

이렇게 만들 경우, 동일한 방법으로 

가차의 대상이 될 playerId를 나름 유연하게 지정할 수 있다.find 의 결과만 있으면 되기 때문에, 

 선수를 find 하는 where 부분에 레어도 라는게 들어간다거나 하는 등.. 일정 범주의 가차를 만들 수 있게된것 !!

 

 

 

그 외에...

보유 선수 조회 기능을 다른 조원이 작업하셨는데 

따지고 보면, roster 기능은 다 내가 맡았어야 되는 상황이라 코드 주도권을 넘겨받았다 !!

 

이전, 로그인 한 계정의 모든 보유 선수를 출력해주는것 에서 

distinct 를 활용하여, playerId 와 enhanceCount 가 동일하게 존재하는 경우 

조회 결과에 포함하지 않도록 했다. 즉, 중복된 것은 버려지고, rosterId 가 가장 낮은선수 하나만을 조회하게 된다 !

 

중복되는 선수는 뭐 하나 다른점이 없기 때문에 깔끔하게 조회할 수 있다.

 

다만, 몇개가 중복되었는지 정도는 표기할 수 있어야 한다.

 

해당 부분은... 내일 알아보도록 하자 !!

 

 

 

 

 

 

 

 

 

문제가 살짝 난해한 내용이다.

 

요점은, #이 표시된 위치에 따라 드래그 할 영역을 정해야 한다는 것.

 

 

정답을 구하는 방법 자체는 금방 떠올랐다. 

 

이제 답을 구하러 가야하는데,

늘 그랬던 것처럼 for반복을 하기로 했다. 

 

 

우리가 필요한건 wallpaper[i] 에  #이 포함된 경우와 wallpaper[i][j] 가 # 인 경우

그중 가장 높은값과 낮은값이 필요하다. 

 

제한사항 자체가 그렇게 빡세지는 않기 때문에 for 기본 반복문을 통해서 해당 값을 구하고, 

answer에 담아 리턴해주면 끝 !

 

 

 

추석 연휴 기간동안에도 팀 과제를 진행했지만, 따로 TIL에 기재하지는 않았다.

 

저번 TIL 에서도 말했지만, 모든 휴일과 제출당일을 제외하면 4일밖에 남지 않았기 때문에 (그 중 하루는 오늘 !!)

팀원들과 상의해서 연휴 기간에도 모여서 프로젝트를 진행하기로 했었다 .

 

 

 

현재, 내게 주어진 임무 중, 필수기능에 해당하는 부분은 모두 구현이 완료가 된 상태이다.

 

 

다만, 현재의 roster 테이블의 구성은, 위 그림에서 보는것과 같이

rosterId (PK) ,  계정ID, 선수 Id 로 이루어진  일종의 인벤토리 테이블로 되어있다.

데이터 1개 (행) 당 1개의 선수만을 표시하므로, 선수가 쌓일수록 데이터가 굉장히 많아지는 구조이며,

 

이 형태는 내가 직전 과제인 CH3 아이템시뮬레이터 에서 작성했던 인벤토리 테이블과 정확히 일치하는 구조이다.

 

여기서 !!

차선책 이었던 위 형태의 라이벌이 되는 구조가 있었는데, 

 

그것은 수량 개념 을 갖는 컬럼을 만들고, 데이터 한개가 여러개의 동일한 선수를 보유하고 있음을 표현하는 방식이다.

수량 개념이 있다면 동일 데이터에서 수량만 변할것이므로 사실상 accountId 와 playerId가 일종의 1:1 관계가 되고

데이터의 숫자가 확연히 줄어들게 되므로 장점이 많다.

 

 

그럼 왜 해당 방법을 버리고 데이터가 우후죽순 늘어나는 방법을 채택했는가...?

 

그 이유는

 

 

선수 강화 기능에 대한 고려를 한 결과이다.

 

선수 강화를 적용하는 방식은 크게 두 가지로 나눌 수 있다.

 

 

첫 번째 방법

데이터 베이스에 해당 선수의 강화 결과에 대한 데이터가 전부 넣어버린다.

예를 들면 player 테이블 내에

선수ID1  호날두 +0 공격력 90 수비력78 스태미나 84

선수ID2  호날두 +1 공격력 96 수비력 81 스태미나 86

선수ID3  호날두 +2 공격력 101 수비력 83 스태미나 90 

 

위와 같은 강화 결과에 대한 데이터가 별도의 선수Id 로 '이미' 존재하고 있어야한다.

강화 성공 시, 선수 Id 자체가 변하는 결과가 되는것이다.

두 번째 방법

그림처럼, 선수 테이블에 enhanceCount 를 넣고 강화 수치를 표시해서,

별도로 강화 수치가 기록된 테이블의 데이터를 참고하여...

실제 강화된 능력치가 적용되어야 하는 순간에 해당 수치만큼

능력치를 더해서 적용하는 방법이다.

 

왜 그림 자료가 있는가 하면, 이 두 번째 방법을 사용중이기 때문이지 !!

 

 

아니 그럼 두 번째 강화 방법에 수량까지 추가하면 되는거 아닌가? 하는 의문이 생긴다.

 

그럴싸 하지만, 위 방법대로라면,

수량이 50으로 되어있는 데이터의 선수를 강화를 하면 50명이 전부 강화되는 일이 발생할 것이다.

이런 사태를 피하려면? ==> 강화 결과 선수 ID 자체가 변해야 한다. ===> 강화 결과 새로운 선수ID 필요

=== 위의 첫 번째 강화 방법이 필요

 

위 방법을 사용한다면, 선수 하나를 새로 등록하는데

5강화 까지만 데이터를 추가한다고 해도 6개씩의 데이터를 입력해야한다.

 

따라서, 1선수 1데이터라 해도 데이터가 우후죽순 늘어날 가능성이 희박한 환경(과제) 인 점,

굳이 +0 +1 +2 +3 +4+5  데이터베이스 노가다가를 할 필요가 없다는 점에서  !!!

본문 초반에 나온 roster 의 방식이 사용되었다고 할 수 있다. 

 

해당 방식을 채택한 이유에 대한 설명은 여기까지 하고,

다음은 오늘 해결된 코드 내용을 간략히 설명해 볼까 한다.

 

 

해당 코드는, 내가 담당(부) 로 되어있는 선수 뽑기 ! gacha에 해당하는 부분이다.

문제의 코드를 살펴보자.

 

 // create 를 반복문으로 돌렸습니다...
    const manyPlayer = async function aabb(accountId, gachaTry) {
        // 가차 선수 범위
        let answer = [];
        for (let i = 0; i < gachaTry; i++) {
            let randomPlayer = Math.round(Math.random() * (findMaximumPlayerId.playerId - 1)) + 1;

            // 랜덤 선수 획득
            const getGacha = await prisma.roster.create({
                data: {
                    playerId: randomPlayer,
                    accountId: +accountId,
                },
            });

가챠 기능 자체에 문제가 있던것은 아니지만, 

위의 코드를 보면 누가 보기에도, create 가 반복문을 통해 돌아가는것은 바람직하지 않아보인다.

 

10번의 뽑기를 진행한다면,

prisma.roster.create 에 해당하는 부분이 10번이 반복되어버리는.... 매우 참담한 상황이다.

create 반복?!?

 

 

어느정도 해답에 가까운 정보를 검색을 통해서 알고있긴했지만....

바로 createMany  prisma메서드를 사용하는 것이다.

 

문제는 createMany의 사용법이 너무 난해했기 때문에 접근을 전혀 하지 못하고 있었고...

튜터님을 통해 문제를 해결하기로 했다.

 

 

그 해답은 매우 심플했다....

 

createMany 사용법에서 알려주는것 처럼,

data 를 [] 배열... 즉 json 의 형태로 때려 넣어주면 알아서 다 생성한다는 것이다 !  

마치 .map()  메서드의 실행 방식처럼 말이다.

 

 

위의 형태로 만든 뒤,

resultGacha  라는 변수가 가진값이 =  [{playerId : 랜덤으로뽑힌number, accountId : 뽑기한유저ID}, {playerId ...}]

의 형태로 만들어 준다면, createMany가 정상적으로 작동하게 된다.

변수부분에 데이터를 잘 가공해서 넘겨줘야 하겠지만, 무려 반복문도 필요없고 2줄 분량의 코드로 줄어들었다.

 

 

여기서 answer = resultGacha 를 반환하는 함수를 따로 만들어줬고, 

약간 조잡해 보이긴 하지만, create 전체를 반복문으로 돌리던 참담했던 과거와 비교했을 때,

무엇보다도 데이터 베이스를 조회하고 create 하는 횟수가 확연히 줄어들었다.

 

오늘도 문제 한가지 해결 !!

 

 

개인과제가 종료되기 무섭게, 팀 프로젝트가 발표되었다.

 

 

과제 기한은 09.13 ~ 9.25일 이다.

꽤나 길어 보이는 기간에 함정이 있었으니..

 

발제 당일과 제출하는 날과 휴일을 제외하면 19, 20, 23, 24   4일의 기간이다 !

 

크흠........

 

 

오늘의 목표

 

 

와이어 프레임

해당 팀 프로젝트는,  저번 개인과제와 마찬가지로 백엔드 중심의 구현에 초점이 있기 때문에,

프론트 부분은 구현을 안해도된다.

추후, 구현하게 되더라고 최대한 간단하게, insomnia 인터페이스와 유샤한 느낌으로 구성했다.

 

 

API 명세서

팀원과 상의하며, 작성한 API 명세서.

현재 1차적인 역할 분담까지 완료된 상태이다.

작업 진행속도나 상황에 따라 유연하게 바뀔 예정 !

 

 

ERD 

 

최초 계획에서 이미 피드백을 받고 수정이 이루어진 상태다.

 

불필요하다고 판단되는 Accounts_info 가 Accounts 에 병합되었고, 

 

그 외 players (선수) 의 내용을 참조가 아닌 복사해와서 쓰는  Roster (인벤토리 선수목록) 같은 형태는 

있어선 안된다는 피드백 (보안 문제, 유지보수가 불가능 수준이기에 현업에선 있을 수 없는 형태) 

을 통해 players 가 선수의 내용을 담고, 후에 강화정보는 Roster 를 통해 참조되기로 했다.

 

 

관련 지식이 없어서  전혀 모르고 있었지만, 튜터님께 들을 내용은 충격적이었다.

기존에 예상했던 방식 ->

아이템DB -> 해당 DB에서 아이템을 복사해서 인벤토리로 가져옴 -> 그 후 자유롭게 +- 제련 강화 기타 등등 작업하며 사용

 

이런 형태로 아이템의 흐름을 예상 했는데, 완전히 틀린 내용이었다.

 

이유로는, 

 

첫 번째 !!

만약 아이템이 상당량 풀린 상태에서 아이템의 수정 (패치로 조정) 이 이뤄져야 한다면, 

베이스db에서 수치를 조정하는건 당연하고, 

풀려있는 모든 아이템을 추적해서 직접 조정해야한다. 

이와 비슷한 내용의 유지보수가 현실적으로 불가능해 진다.

 

두 번째 !!

위와 비스무리한 이유로, 아이템이 어떤 과정을 통해 이런 결과로 변조되었는지 알 수 없게된다.

이는, 해당 아이템 데이터가 조작되어도 딱히 검증할 방법이 없는것이라 할 수 있다.

같은 이유로, 아이템의 강화 내용을 되돌리는 기능 같은것도 있을 수 없게된다..

 

따라서 ! 위의 ERD 표 처럼,  plalyers 의 값을 참조 하되, 추후에 강화기능을 만들게 된다면

roster 테이블에서 강화와 관련된 데이터를 관리하게 될 것이다.

 

계획은 이 정도 선에서 마무리 되었고 ,

 

내가 맏게된 파트는 팀 편성 관련 API 등등 이다. 

 

 

일정 상, 추석과 주말에 과제를 진행해야 겠지만,

 

이번 팀원들과 호흡이 잘 맞을것 같아 벌써부터 기대가된다 !!!!

 

 

 

 

늘 그래왔듯이,

과제 제출하는 날이 되면 미처 발견하지 못했던 오작동 코드나, 오류들이 발견된다.

 

발견되는건지 발생하는건지 모르겠다

 

 

 

1. 아이템 판매시 장착된 아이템이 inventoryNumber 가 제일 낮은 경우, 그대로 팔려버린다.

 

이는, 대상 item을 find 하는 과정에서 equippedItem 의 여부를 묻지 않고 조회했기 때문이다. 

으음... 기초적인걸 놓쳤다.

이렇게 뜬금없이 장착된채로 아이템이 팔려버리면,

장착 해제+판매금획득+ 장착했던 능력치는 유지 라는 대환장 사태가 벌어진다.

 

어디까지나 개인 과제이기 때문에 찾는다면 고치면 되지만,

실제 서비스중인 게임이었다면 정말 끔찍하다.

 

조회시, where문에 equippedItem : false 로, 장착중이지 않은 아이템만 조회하게 하면 해결!

 

 

 

2. 해당 캐릭터의 가장 낮은 inventoryNumber를 탐색하는 과정에 문제가 발견됐는데, 

 

 

광분하여 작성한 Rawquery 부분에 오점이 있었다.

 

마음을 가다듬고...

 

무아지경으로 작성한 이 코드를 재 해석 해보면,

우선 findTargetItem 은 단순하게,

inventory 테이블에서 대상이 된 characterId 가 가진 아이템 중, inventoryNumber가 가장 작은 아이템

한 개를 조회한다.

 

조회 결과가 없을경우, 해당 캐릭터는 아이템을 한개도 보유하고 있지 않은 상태인 것이기에

해당 케이스는 따로 inventoryNumber 1을 부여하게 된다.

 

조회 결과가 있을 경우, 가능한 낮은 inventoryNumber  를 부여받기 위해 탐색을 진행하는데

이 부분이 로우쿼리 부분에 해당하며,

쿼리를 해석하면, 

inventory 테이블에서, inventory_number 가 가장 작은 결과 하나를 조회한다. 

그런데, 캐릭터 id가 대상이 된 캐릭터 Id 인것중에서만, 게다가  inventory_number 값에 +1 을 더해서 검색한다.

그 캐릭터 현재 가지고 있는 itemNumber 를 제외하고 

 

 

쉽게 말하면, 

그 캐릭터가 보유중인 아이템 중에서 가장 낮은 inventoryNumber 에서 +1 했을 때 값이 비어있는 값을 찾는다.

 

굉장히 본래 의도와 맞지만 함정이 있다.

탐색 자체를 현재 보유중인 값 부터 시작한다는 말이다.

 

이 말은, 해당 캐릭터가 보유한 itemNumber 의 최소값이 5 라면, 

1~4 가 비어있음에도 불구하고 5부터 탐색을 시작하게 된다.

 

 

만약 인벤토리 사이즈가 10 일 때, 

해당 캐릭터가 itemNumber 10인 아이템 한개만 들고 있다면,

해당 캐릭터는 더 이상 아이템을 획득할 수 없는 상태가 된다.

10부터 탐색하기 때문에 결과가 11이 되기 때문이다.

 

우연히 찾아낸 오류 이지만, 해결 방법은 간단했다.

 

아이템을 보유하고 있지 않을때는 1을 부여했던 것 처럼,

1을 보유하고 있지 않은 경우는 1을 부여하면 된다.

 

 

정말, 너무 만들고 싶어서 만들었지만

왠지 쓸데 없는 코드인것 같고...

로우쿼리 라고는 해도, 탐색 과정이 효율적이지 않은듯 한 데다가,

필수 구현 사항들과는 거리가 먼 코드라서 마음이 아프다...

 

또르르

 

 

아무튼 ..! 추가적으로 위에 있는 내용 처럼, 이전에 만들어놓은 캐릭터의 inventorySize 컬럼을 이용해서 

인벤토리의 한계를 적용해 보았다. 

 

전체 app 상에서, 아이템이 inventory로 추가되는 경우는 

해당 아이템 구매 API가 유일하기 때문에 여기저기 사용되어야 할 일은 없다.

 

 

그 후에, 

알고리즘 코드카타 -> 스탠다드반 강의  콤보로 인해서 과제 제출 마감이 임박하게 되었고,

 

많이 아쉽고 많이 부족한 채로 결과물을 제출하게 되었다.

 

 

부랴부랴 만든 API 명세서

 

 

 

아쉬운 점과 부족한 점

과정의 문제

 

우선, 해당 과제가 발제됐을 때 미처 듣지 못한 강의가 남아있었기 때문에

시작 과정 부터가 험난했다. 꽤 많은 분량의 강의가 남아있었고

과제는 이미 발제가 되었고...

 

빨리 과제를 시작하고 싶다는 기대,

내가 이번 과제를 잘 할 수 있을까? 하는 불안감,

강의 내용은 머리에 잘 들어오지 않아 답답함,

 

오만가지 생각이 교차하며 과제 시작부터 삐그덕 거렸기 때문에, 

만족한 결과가 나오지 않은것은 당연한 지도 모른다.

 

결국 강의를 들으면서 동시에 과제를 진행하게 되었고,

해당 부분에서 학습효과와 집중력이 떨어질 수 밖에 없었다.

 

과제 기간에도

스탠다드반 수업(CS), 챌리지반 강의(복합), 알고리즘 코드카타 모두 평소처럼 병행되었기에

12시간이 짧다고 느껴졌으며,

실제로 과제 기간동안 오후9시에 학습을 마친 날이 없었다.

 

다음 과제부터는 필요한 강의 부분을 최대한 발제 전에 마치도록 시간을 분배하여

이번과 같은 일이 생기지 않도록 해야겠다.

 

부족한 점

이번 과제는 부족한 점이 너무나도 많다

 

처음 사용하는 데이터 베이스, 코드작성을 위한 ORM,

의 서버를 대여하는 AWS RDS

 

express 구성, node 구성,

의 서버를 대여하는 EC2,

 

미들웨어 함수, 오류에 대한 처리, 

인증과 인가.

 

전부 너무 생소한 개념이었고, 결과적으로 이해도, 완성도 모두 부족한 채, 과제를 제출하게 되었다.

 

하지만

이런 핑계는 소용이 없다는 것을 알고있다.

 

앞으로 배울 내용들도 항상 새롭고 전부 생소 할 것이다.

 

언젠가는 아예 다른 언어를 사용해야 할 수 도 있다.

 

물론, 아직 조급해 할 필요 까진 없다고 생각한다.

이제 겨우 본 과정 한 달이 지났을 뿐이다.

 

정말로, 열심히 하고 있다고 당당하게 말할 수 있기 때문에,

지금처럼 학습을 진행하되, 위와 같은 일이 일어나지 않도록 시간 분배를 잘 해야하며,

같은 문제가 반복되지 않기 위해서는 기본기를 꾸준히 단련해야겠다. 

 

 

주눅 들지 말자.

포기하지 말자.

 

 

 

내일 점심시간 전까지 과제를 제출해야 하기 때문에, 사실상 오늘이 마지막 날이다. 

 

 

 

도전 과제의 기능까지 구현은 모두 완료된 상태이다.

모아 놓고 보니까 API 의 수가 꽤 많은것을 확인 할 수 있다.

 

뭐 하나 쉬운게 없었다 !!

 

 

최종적으로 과제 제출을 위해선, 

 

 

마무리 단계인 AWS 배포까지 진행해 보도록 하자.

 

윈도우 환경이기 때문에 Git Bash 로 진행했고, 

EC2 구성은 이전에 강의를 듣고 중지시켜놨던 인스턴스를 다시 활성화 시켜서 사용하기로 했다.

 

git을 통해 파일을 받아올 것이기 때문에, gitignore 설정이 잘 되어있는지 확인하고  push 해놓자.

 

.env 파일이 같이 업로드 된다면 대여한 서버에서 무슨일이 생길지 모른다.

 

그렇다면 업로드 하지 않은 .env 는 어떻게 ubuntu 에게 보낼까?

 

 

검색 결과, vim 을 통해서 .env 를 생성하거나 수정 할 수 있다는 사실을 발견 !

 

 

불편하기 짝이없는 linux 환경을 잠시나마 경험할 수 있었다.

 

:wq 를 통해 해당 작업을 저장하고 종료할 수 있다.

 

이제 실행만 app.js를 실행하기만 하면 !

당연히 안된다. 구동에 필요한 패키지를 설치해야 하기 때문이다.

 

yarn  명령어를 통해, 패키지를 설치 하면 본격적으로 

EC2 의 IPv4 주소와 포트를 통해, 배포가 가능하다 !

 

insomnia 를 이용한 요청과 응답이 정상적으로 이루어지는 모습이다.

 

예상치 못한 난관이 있을것만 같았지만, 큰 어려움은 없었다.

방법을 깨달았으니

 

남은 시간동안은 다시 코드를 재정비하고, 업로드 후 재설치하고 배포할 시간이 될 듯 하다.

 

 

다음 내용으로, 

과제 내내 나를 괴롭혔던 부분에 대한 해답이 밝혀졌다 !

 

예상했던대로, header 를 통해서 토큰을 발행하면

클라이언트가 해당 토큰과 함께 요청을 전달해 주는것이 맞는 내용이었다.

 

로그인을 통해, jwt 를 발행하고 전달하는것은 cookie와 크게 다르지 않지만, 

 

 

해당 토큰은 insomnia 기준으로 authorization Headers 를 통해 클라이언트에 발행하고,

 

 

클라이언트는 서버의 인가가 필요한 사항에 대해서, Auth 에 TOKEN을 담아서 서버에 요청을 보내게 된다.

 

요청하며 보낸 토큰이 비정상적이라면, 당연히 정상적인 응답을 받을 수 없다.

 

 

계속 마음에 걸렸던 부분을 해결한 것 같아 한결 편안해졌다.

나머지  미흡한 부분도 많지만, 벽 처럼 느껴졌던 과제를 어느정도 해결 해 낸것 같아서 다행이다.

 

 

 

 

어제 고민했던 캐릭터 검증 코드를 미들웨어로 만들기로 했다. 

 

문제는, 실제로 미들웨어를 어떻게 작동되게 하는지 모르고있다는것...

미들웨어에 대한 개념 자체가 부족한 상태이다.

 

그 결과.....

 

해당 미들웨어를 갑자기 API 본문에 함수호출 형태로 작성을 하는 사태가 벌어졌다.

 

굉장히 민망한 상황이지만, 이게 잘못된 방법이라는 것은 바로 느껴졌기 때문에

미들웨어에 관한 학습을 다시 진행한 결과,

 

 

해당 형태로 순차적으로 미들웨어가 실행될 수 있게 하였다.

민망했던 위의 코드와 차이점을 살펴보면, 

 

처음 작성한 코드는 미들웨어(async 핸들러) 내부에서 호출되었기 때문에

return 을 반환 하더라도 다음 코드가 '당연히' 실행된다.

 

하지만,

아래에 작성한 코드는, 호출된 미들웨어가 next()를 받지 못하고  return 된다면

결국 => { } 의 내용으로 넘어가지 못하고 그대로 종료된다.

 

추가로 !

CharacterAuth(req, res);  형태는 그냥 함수의 호출이기 때문에 아예 잘못된, 완전 틀려먹은 접근이라고 생각했는데,

미들웨어 자체가 함수의 호출과 비교해서 크게 다를바가 없기 때문에, 호출한 위치가 잘못된 것이고 !

함수로서 호출하는 발상은 100% 틀려먹은 생각인것은 아니다 ! 라는 피드백을 받을 수 있었다.

 

 

 

다음으로 구현한 API는, 도전 기능에 해당하는 장비 장착 API 이다.

뭔가 많은 과정들이 SKIP 된거 같긴하지만...

 

해당 과제,  그것도 도전 기능의 BOSS 에 해당하는 API 라고 생각되는 부분이다.

 

 

API요구 사항은 위와 같다.

해당 내용을 토대로, 구현하기 전에 구상을 먼저 해보면,

 

우선, 해당 API를 실행하기 위해서는 !!!

 

로그인 인증을 거쳐야 하며, > login DB 조회

param으로 전달받은 characterId 도 검증해야하고 > character DB 조회

인벤토리의 아이템을 장착해야 하기 때문에 > inventory DB 조회

장착한 아이템의 능력치를 참조해야 하기 때문에 > item DB 조회

모든 테이블이 필연적으로 한 번씩, 조회될 수 밖에 없다.

 

그리고, 장비의 장착으로 인한

캐릭터의 능력치가 update, 아이템 상태의 update 또는 delete 등

데이터베이스의 수정이 여러번 발생하게 되기 때문에, 트랜잭션 구성을 생각해 둘 필요가 있다.

 

 

첫 코드부터 난관이었다. 

 

이유는, 장착 대상이 된 인벤토리의 아이템을 특정해야 하는데, 

characterId 와 itemId 로는 정확한 inventoryId 를 특정할 수 없다.

같은 캐릭터가 동일한 아이템 여러개를 인벤토리에 보유할 수 있기 때문이다.

11 캐릭터가 13 아이템 2개를 가지고 있다

제시한 두 가지의 정보로만 검색을 하면, 복수의 값이 결과로 나올 수 있다는 것이다.

어떤 아이템을 장착해야 할 지 

 

해결방안

1. 인벤토리의 PK에 해당하는 inventory_id 를 추가로 입력받아 진행한다.

-> 과제 요구사항에 벗어나며, 별로다 !!

 

2. 딱히 쓸데 없었던 inventory_number 라는 컬럼을 활용해 보자.

--> 예상되는 문제점이 있으나, 현 상황에선 큰 문제는 아니기 때문에 진행 !

 

 

 

사실, 위에 올린 이미지가 inventory_number 를 활용한 이미지 이다.

여기서, inventory_number는, 어떤 아이템이건 획득 당시에 

 

해당 캐릭터가 보유한 아이템들 중, 가장 높은 inventoryNumber +1 의 값을 부여한다. 

 

본래 의도는 가장 최소 값을 찾아 들어가게 할 예정이었으나, 

생각보다 로직이 복잡하고, 시간이 급박하기 때문에

 

일단은, 임시로 같은 캐릭터 id 내에서 중복되지는 않는 값을 갖도록 구현을 해 놓았다....

때문에 그다지 의미있는 컬럼이 아니게 되었지만,

결과적으로, 현재는 해당 값이 가장 작은 item을 지정하는 방향으로 구현이 된 상태다.

 

 

추가로,

이미 장착중인 아이템 중에,

위에서 특정한 아이템과 같은 타입인 것이 조회될 경우는 

에러를 리턴하도록 하고, 해당 사항이 없다면

 

 

 

아이템DB를 조회하고, 해당하는 능력치를 올려주는 update 문을 작성해서 마무리 했다.

 

일단 작동은 잘 되고 있기에, 여유가 될 때에 구상해뒀던 트랜잭션 부분이나, 

inventoryNumber 가 최소값을 찾아 들어가게 하는 방법을 적용할 예정이다.

 

 

 

 

네트워크 계층이란?

 

OSI 7계층 중, 3계층에 속하는 내용으로, 망 계층 이라고도 불립니다.

 

네트워크 계층의 대표적인 역할은,

라우팅(Routing) 과 포워딩(Fowarding) 입니다.

 

 

라우팅은

길 찾기에 해당하는 내용이며, 네트워크 계층 내에서 Control Plane 으로 나누기도 합니다.

출발지에서 목적지 까지의 경로 중, 가장 효율적인 경로를 탐색하는 것을 말합니다.

 

포워딩은

네트워크 계층 내에서 Data Plane 으로 나누기도 하며,

최선의 경로를 따라서 실제로 데이터를 전달하는 기능을 말합니다.

 

 

데이터 링크 계층과의 차이

데이터 링크 계층은 인접한 두 노드 간의 전송을 담당하는 것이고, 

네트워크 계층은 전체 네트워크 상에서 최종 수신지 까지의 전송을 담당합니다.

 

 

 

IP (인터넷 프로토콜, Internet Protocol)

목적지 까지 데이터를 전달하는 기능을 수행하고, 주소를 관리하는 기능을 수행합니다.

IP를 통해서 포워딩이 이루어진다 라고 볼 수 있습니다.

IP 주소 라고 불리는 인터넷 상의 고유 식별 번호를 통해 실제 데이터의 출발지와

목적지 등 각각의 주소(위치) 를 정의 할 수 있습니다.

 

 

 

DHCP (Dynamic Host Configuration Protocol)

클라이언트에게 동적으로 IP 주소를 할당하는 방법을 제공하는 프로토콜 입니다.

 

DHCP 의 특징

-주소의 대여시간 갱신 (연장)

-동일한 주소의 재 사용 가능

-네트워크에 접속하고자 하는 이동 사용자 지원

 

 

 

NAT ( Network Address Translation)

라우터 등의 장비에서 사설 IP를 외부IP 로 변환하는 기술입니다.

 

만약, 네트워크 내에 엄청나게 많은 호스트가 있다면, 호스트 마다 IP 주소를 할당하는데에는

너무 많은 IP 주소가 필요할 것 입니다. 하지만 실제로는 외부 인터넷이 내부 인터넷에 존재하는

모든 호스트에게 IP 주소를 직접 할당 해주는 것이 아닌, 라우터에게 IP 주소를 할당해줍니다.

결국 라우터 내부의 네트워크는 사실상 모두 같은 IP 주소를 사용하는것 보일 수 있습니다.

 

하지만, 내부 네트워크에서만 사용할 수 있는 또 다른 IP 주소를 부여받게 되고 이를 사설 IP 라고 부릅니다.

 

결과적으로, 내부 네트워크에 존재하는 사설 IP를 외부 IP 로 변환 및 매핑시켜주는것이 NAT 라고 할 수 있습니다.

 

+ Recent posts