즐거운 토요일... 코딩을 시작해보자.

 

오늘의 목표는 인벤토리를 어느정도 구현해보는 것이다.

 

구현에 앞서서...

인벤토리란 무엇일까?

흔히, '가방' 으로 표현되는 인게임 기능으로, 캐릭터가 항상 들고 다니는 

아이템 보관함 같은것 이라고 할 수 있다.

어플리케이션 마다 인벤토리의 형식은 많은 차이가 있지만,

내가 생각하는 인벤토리의 가장 기본적인 기능은,

 

아이템의 소유자를 명시하는 테이블 이라고 보고 있다.

 

가질 수 있는 아이템의 한계치, 혹은 수량의 중첩 등 부가적인 기능들이 있지만,

기본적으로 어떤 아이템을 '누가' 소유하고 있고, 그 소유자만이 해당 아이템을 사용 할 수 있게 하는것이

인벤토리의 가장 기초적인 기능이라고 생각된다.

 

 

 

그것을 중점으로 생각하여 우선 테이블을 만들어 보았다.

 

inventoryNumber 는 아직 어떤 기능을 할 지 모르겠지만 왠지 필요할 것 같기에 일단 넣어둔 것이고,

 

결국 캐릭터의 Id 와 아이템의 Id만 있다면 아이템의 소유를 명시 할 수 있을것이라 생각하고 만들어봤다.

 

해당 인벤토리 테이블은 서버 내의 '모든' 캐릭터가 소유한 '모든' 아이템을 담게된다.

 

때문에, 인벤토리는 동일한 캐릭터가 여러번 들어갈 수 있어야 하며, 

같은 아이템 또한 여러개의 소지가 가능하기 때문에,

itemId 와 CharacterId를 모두 1:N 관계로 설정했다.

 

이를 통해 만들어진 인벤토리의 모습 

 

여기서 한가지 문제점 (한가지 만은 아닐테지만)을 발견했다....

 

 

현재로서는,

캐릭터의 Id를 특정 할 수가 없는 상태이다.

 

왜냐하면 지금 구현된 부분은, 계정 로그인만 하고 캐릭터는 따로 접속하는 개념이 없기 때문에,

계정 외에는 특정할 수 있는 부분이 없다.

 

해결 방안..?

 

1. 한 계정 당 캐릭터 하나로 제한하여 사실상 캐릭터===계정으로 만들어버린다.

    -> 제작 의도와 거리가 멀기 때문에 탈락

 

2. /api/:character_id/ item~어쩌구 저쩌구

   - 캐릭터 id를 params 로 받는 방법.

   -> 거의 모든 api 에서 해당 character_id가 계정내 캐릭터가 맞는지 검사해야한다.

   -> 유저와 서버와 개발자 모두 별로인 방법

 

3. 로그인 처럼 캐릭터 접속 기능을 만든다.

   -> 지금 생각나는 방법 중에선 가장 그럴싸하다.

 

 

당장 해보자. 

계정 로그인 API 와 캐릭터 삭제 API의 형식이 묘하게 합쳐져서 캐릭터 접속 API 가 되었다.

 

하지만, 문제를 해결하려 할 수록 오히려 문제가 늘어가고 있다...

 

접속에 성공했다면, 해당 캐릭터Id를 어디에 저장해야 할까?

 

쿠키를 두개 쓴다? 제대로 참고할 수 있을지도 잘 모르겠고,

모든 매 통신마다 보내는 쿠키가 하나 더 늘어나는것은 좋지 않은데다가,

 

 

해당 과제 요구사항이 뜻하는 것이 아직 제대로 이해가 되지 않기 때문에

어떻게 해야할지 모르겠다.

 

진전이 없기 때문에, 일단은 지금의 cookie 를 계속 사용하고 나중에 방법을 다시 알아보기로 했다.

 

다시 돌아가...자 마자 문제 발생 !!

 

authMiddleware 가 로그인정보 + 캐릭터 정보 모두 검증하게 만들 계획이었지만,

 

캐릭터 접속을 하기 위해서는 로그인이 되어야 하기 때문에  authMiddleware  검증이 필요하다.

 

마치,

자물쇠가 걸린 방 내부에 자물쇠 열쇠가 있어서 못들어가는것 과 같은 상황이다.

 

해결방안

1. 캐릭터 접속까지 authMiddleware 검증 없이 어떻게든 해결한다??

   -> 캐릭터 접속, 생성, 삭제 등 로그인 만 하면 되는 기능들을 전부 직접 검증해야한다

 

2. 로그인 시 임의의 캐릭터 정보 값을 부여하여, 캐릭터 접속을 가능하게 한다.

   -> 임의의  값 일때 캐릭터 접속 이외의 검증은 통과해선 안되기 때문에

        검증을 필요로 하는 모든 API 에 추가 조건을 만들어야 할듯..

 

3. authMiddleware 를 2가지로 나눈다 !! (계정 검증 / 계정+캐릭터 검증) 

  -> 정말 내키지 않는 방법인데 일단 이 방법이 그나마....

 

 

생각해보면 

로그인만 해도 가능해야하는 API (캐릭터 생성, 캐릭터 접속, 캐릭터 삭제) 와 

캐릭터 접속까지 해야 가능한 API 어느정도 분리되어야 하기 때문에,

authMiddleware 2가지로 나누는게 아주 나쁜 선택은 아닐것이다.

( 평일이 되면 관련 내용을 튜터님에게 피드백 받아보자 )

 

어렵진 않으니 만들고보자.

 

그냥 복붙으로 두개로 나눈다음에, 필요한 곳에서 각각 불러오고, 적용하면 끝이다.

 

캐릭터 접속까지 한 경우를 검증하는 connect.auth 에서는

추가로 char 값이 이상할 때 에러를 발생하게 하면 된다.

 

이 작은 차이 때문에 복사를 해야한다고?! 생각이 되긴한데 다른 방법이 당장 떠오르지 않는다..

 

 

 

캐릭터 접속까지 요구하는 API
캐릭터에 접속
접속 후 동일한 API가 잘 처리된 모습

 

 

이 타이밍에..... 엄청난 반전이 있었으니...

 

 

 

 

이럴수가 ...?!?!?!?

 

 

도전기능

에 해당하는 부분에서, 캐릭터ID 를 param 으로 받는다는 내용이 기재되어 있었다...

 

필수 과제만으로 벅찰것 같아서 자세히 확인을 안해본 도전과제에

저런 내용이 있었다니 !!

 

사실 이는 해당 글의 상단에 있는

 

 

2번 해결방안에 해당하는 내용이었다.

그 해결 방안이 과제에서 제시한 방법이었던 것이다.

 

음.. 별로인.. 방법 아닐지도 ? ㅎ

태세 전환

 

 

 

 

 

 

시작에 앞서서, 어제 문제가 됐던 부분을 다시 살펴보자.

 

 

이번에 사용한 방법은, findFirst를 where 까지만 우선 실행해서,

character.userId 를 얻어내는 방법이다.

 

그 다음 한번 더 find 하는 효율적인 작업을 해서, 

Money에 삼항 연산자를 적용하는 방법이다.

 

 

의도한 대로 작동하지만, 조회 한번 하는데 쿼리를 3번이나 불러오는 현상이 목격되었다.

where 로 2번, select 로 한번 불러 오는 듯 하다.

 

 

음...

character.userId 를 참조하는 쉬운 방법이 분명히 있을것 같은데,

상당히 기초적인 것을 놓치고 있는 느낌이다.

그게 아니라면, where 와 select 사이에서 뭔가 해 줄 수 있을것 같은데, 아직 잘 모르겠다.

 

 

 

 

우선 어제 계획한대로, 강의 부터 모두 듣고난 뒤에 

계속해서 과제를 진행해 보았다.

 

 

오늘 진행한 부분은 아이템 관련 부분이다.

 

위의 아이템 생성 API 는, 로그인 없이도 아무나... 만들 수 있으며,

만들어진 아이템은 items에 추가된다. 

 

items 테이블

 

 

 

조회 기능도 만들어 보았다.

마찬가지로 아직 error 잡는 부분 등은 미흡

 

itemId 2의 상세 조회 결과

잘 작동하는 모습 !!

 

오늘 구현한 기능은 많지 않지만, 

강의를 모두 들었기 때문에 다음 주 부터는 조금 더 속도가 날 것 같다.

 

 

 

 

 

 

CH 3 아이템 시뮬레이터 과제 !

 

아직 강의를 다 듣지 못했지만

조금 급한 마음으로 과제를 시작해보았다.

 

내가 할 수 있는게 맞는지 아닌지가 궁금했기 때문이다.

 

 

 

강의를 토대로 만든 결과 나름대로 잘 작동하는 모습이다 !

 

아직 error 처리라던지,  디테일한 DB 셋팅 등등  할 일이 많지만...

 

그래도 못할 건 없겠다 라는 생각이 들어서 안심이 됐다.

 

 

그래서.. 

 

오늘의 문제 !!

 

 

캐릭터 조회 API 만들기 ..

 

우선, params 를 입력받아 해당 캐릭터Id를 조회하게끔 구현을 해 보았다.

 

문제는 캐릭터 조회가 아니라...

 

바로 이 두 줄에 해당하는 부분이다.

 

 

 

 

아무리 생각해도, 로그인했을때  기록된  userId 와,

현재 조회하는 character 가 가진 userId 가 같은지를 비교하는게 맞는 방향 같은데,

 

로그인 했을 때 userId 는 req.user 가 가지고 있고,

문제는 조회한 character 가 가진 userId 인데,

 

방법을 모르겠다.

방법을 왜 모르는지 모르겠다 !!

 

위에 코드는,

일단 userId를 select 하고  그 select 한 userId를 토대로 비교해서 

Money를 삭제할지 말지 정하는 if문을 추가한 방식이다.

 

문제가 되는 사항은,

userId는 조회 할 필요가 없다.

그래서, userId를 셀렉트 하지 않으면? 

아래 if 문에서 userId를 참조할 수가 없게된다..

userId select를 : false 로 바꾸면?

 

그럼 애초에 select 하지 않아서인지, 참조가 되지 않는다.

 

 

사실, 이 단계까지 오는데도 너무 오랜 시간이 소요되었기 때문에...

수리를 할 시간이 부족했다.. 

이미 자정이 지나버린 시간

 

 

결국,

userId 까지 select 하면 아무튼 의도대로 작동하는 상태

에서 마무리가 되었다. 수리는 좀 나중으로 미루고...

 

 

내일은 조급한 마음을 가라 앉히고 다시 강의를 듣는것에 집중해야겠다.

 

저번 시간에 배운 1계층 - 물리 계층에 이어서,

오늘은 2계층인 데이터 링크  계층에 대해 알아보자.

 

 

데이터 링크 계층 (Data Link Layer)

OSI 7 계층 중, 2계층에 해당하는 내용으로,

- 직접 연결된 서로 다른 2개의 네트워킹 장치간의 데이터 전송을 담당

- Network 장비 간에 신호를 주고받는 규칙을 정하는 계층

- Network 기기 간에 Data를 전송 + 물리 주소를 결정

- 장치 간 신호를 전달하는 물리 계층을 이용해서, 네트워크 상의 주변 장치들 간에 Data를 전송

- Data들을 Network 전송 방식에 맞게 단위화 해서, 해당 단위를 전송

  .. 이때 전송되는 Data를 Frame 이라고 함 !

- Data Link Layer 에서 최종적으로 이더넷 헤더/ 트레일러가 붙는다.

 

 

주요 기능

프레이밍 (Framing)

- 물리 계층으로부터 받은 신호들을 조합해서 프레임(Frame) 단위의 정해진 크기의 Data Unit으로 변환

 

오류 제어 (Error Control)

- Frame 전송 시 발생하는 오류들을 처리

 

흐름 제어 (Flow Control)

- 송수신 측 간에 Data를 주고 받을 때, 적당한 양의 Data를 송수신 할 수 있도록 Data의 흐름 제어

 

접근 제어 (Access Control)

- 매체 상에 기기가 여러개 존재할 때, 데이터 전송 여부를 결정

 

동기화 (Synchoronization)

- 수신 노드에서 데이터 시작을 알 수있도록 송신 노드가 헤더 부분이 시작되기 전 일정한 비트 패턴 (Frame 구분자)

를 첨가하여 동기화 한다.

 

 

이더넷 (Ethernet)

- LAN 환경에서 Data 를 정상적으로  주고받기 위한 규칙

- Data 충돌을 막기 위해 CSMA / CD 프로토콜을 사용

- 현재에는 UTP 케이블 및 광케이블을 사용

- 프리앰블 / 이더넷 헤더 / Layer 3패킷 / FCS 를 추가해서 Frame 생성

 

 

 

데이터 링크 계층의 링크 종류

Point - to Point 방식 

- PPP, Ethernet 스위치와 호스트 사이의 Point  to Point 

 

Broadcast 방식

- 매체를 공유하는 방식으로 케이블형 Ethernet, 무선 LAN 이 해당

 

 

MAC 주소 (Multiple Access Control)

MAC 주소는 데이터 링크 계층에서 사용하는 주소로, 하드웨어의 생산 당시에 찍혀서 생산되기 때문에,

변경할 수 없는 물리적인 주소이다. MAC 주소는 중복될 수 없고, 한개의 기기에 한개의 MAC 만 존재한다.

 

 

 

입문주차를 끝내고, Node.js숙련 주차에 해당하는 강의 ! 

 

에 대한 이야기를 하기에 앞서서,

 

CH3 의 개인과제에 해당하는 내용이 오늘 공개가 되었다.

과제의 발제 자체는 내일이지만, 어쨌든 해야할 과제가 무엇인지는 공개가 되었다.

 

그 과제는 이름하야...

 

CH 3 아이템 시뮬레이터 과제 !!!

 

 

학습 과제를 끝내고 나면 할 수 있어요!  ==> 이걸 모르면 과제를 할 수 없어요 !

 

발제는 내일이기 때문에 간략하게만 살펴 보았는데,

 

Expreess 로 서버 와 api 구성

AWS RDS -> MySQL 을 사용하여 데이터 베이스를 활용

Prisma를 사용하여 데이터 베이스 컨트롤

AWS EC2 를 이용한 배포

 

와 같은 내용으로 구성되어 있었으며

 

조금 더 구체적으로 들어가면,

1. 회원가입 및 로그인 기능

2. 캐릭터 생성 및 캐릭터의 능력치 설정

3. 캐릭터 상세 조회와 캐릭터 삭제 기능

4. 아이템 생성 

5. 아이템 수정 (강화..?)

6. 아이템 목록 조회 및 아이템의 상세정보 조회

 

도전기능으로는 

1. 아이템 구매 및 판매

2. 인벤토리 기능

3. 장착 아이템 목록 조회

4. 아이템 장착 및 탈착 API

5. 게임머니 획득 API

 

 

이걸 만들라구요 ?!

 

 

어라... 이 감정...?

 

24.08.21 TIL - Roglike 과제를 받은 날

 

 

그렇지만 이번에는 정말로 어려울것 같다는 느낌이 든다...

따로 스켈레톤 코드 같은 것이 지급되지 않는것으로 확인이되어,

더 감이 안잡히는것 같다.

 

 

중요한건 강의를 서둘러서 들어야 한다는거임

 

관계형 데이터베이스 

 

오늘 배운 내용은 전부 여기에 해당한다고 볼 수 있다.

 

저번시간에 학습했던 비관계형 데이터베이스인 mongoDB 와 달리

관계형 데이터 베이스에 해당하는 Mysql을 기반으로 학습을 진행했다.

 

 

관계형 데이터 베이스에 해당하는 Mysql 은 이전에 입문단계에 해당하는 강의를 학습한 적이 있다.

때문에 비교적 이해하는데 큰 어려움은 없었다.

 

차이가 있다면, 입문강의에서 진행했던 내용은  DBeaver 를 통해 이미 작성된 database 를 조회하는

방법 위주로 강의가 진행되었기 때문에, 내용을 따지고 보면 오늘 학습하는 내용과 차이가 꽤 크다고 볼 수 있다.

 

오늘은, 실제로 MySQL 데이터베이스를  AWS RDS 를 통해 직접 구동하여 (대여해서...)

Database 와 table, 그리고 column 에 해당하는 부분을 직접 추가하거나 수정하고, 삭제하는 과정을 학습했다.

VScode 에서  SQL 언어을 사용할 수 있고, 

MYSQL 확장 프로그램을 통해 VScode 내에서 사실 다 할 수 있다.

마이크로 소프트.. 그는 대체...

 

 

 

 

오늘 미약한 공포가 느껴졌던 부분

그것은 바로 Raw Query 라고 할 수 있다.

언뜻 보면, 노드 환경에서 직접 SQL 요청을 보내는 평범한 기능으로 생각이 되지만, 

 

// app.js

/** 테이블 생성 API **/
app.post('/api/tables/', async (req, res, next) => {
  const { tableName } = req.body;

  await connect.promise().query(`
      CREATE TABLE ${tableName}
      (
          id        INT         NOT NULL AUTO_INCREMENT PRIMARY KEY,
          name      VARCHAR(20) NOT NULL,
          createdAt DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP
      )`);

  return res.status(201).json({ message: '테이블 생성에 성공하였습니다.' });
});

 

이런식으로 Raw Query 를 작성하다 보면, 이건 좀 아닌것 같다는 생각이 스멀스멀 들기 시작한다.

 

강의에서는 Raw Query 최대 단점을, 유지보수가 어려운 점을 꼽았는데,

예를 들면,

createdAt 라는 칼럼이  createDate 라는 칼럼명으로 바뀌어야 한다고 가정해 보자.

우리는 Raw Query로 작성한 createdAt를 전부 찾아서 createDate 로 수정해야만 할 것이다.

 

그냥 바꾸지 말죠? 에서 부터,

최악의 경우, 한 두가지를 놓치는 바람에 서버가 다운되거나 데이터가 변조될 위험성도 있다.

 

ORM  등장 (Object Relational Mapping) 

 

앞선 문제들에 대한 대책으로 ORM이 개발되었고, 강의에서는 ORM 중 하나인 Prisma 를 소개해 주었다.

 

 

 

 

ORM 의 최대 장점은, 데이터 베이스가 통째로 바뀌더라도 유연한 대처가 가능하며, ( ex MySQL -> Oracle)

위에 언급된 문제인 Table 또는 cullum 의 수정 정도는 어렵지 않게 대처할 수 있다.

 

 

Node에서 Prisma를 설치할 경우,

schema.prisma 을 내용을 토대로 database 를 추가하거나 수정할 수 있게 된다.

Posts 라는 새로운 table 과 각 cullum 의 설정을 작성한다.

 

SQL 과 Raw Query 사이 어딘가....로 보이는 형태의 언어이지만,

성능이 확실하다고 설명했기 때문에 왠지 호감도가 올라간 상태 !!

 

이렇게 schema.prisma에 작성한 내용을 

 

 npx prisma db push 명령을 통해 push 하면,

 

 

node_modules/.prisma/index.d.ts  의 어딘가에

JS 형태로 작성이 되어진다.

(이 외에도 예상했던것 보다 많은것이 기록된다...)

 

 

 

Prisma를 통해 Posts table과 각 컬럼 속성 설정에 성공한 결과 !

 

 

오늘 학습한 내용은 여기까지 인데, 아무래도 과제 발제 까지 시간이 촉박 하기 때문에,

 

며칠정도는  TIL 의 작성시간을 줄이고 강의를 더 듣는다거나, 

주말을 포기한다거나 하는 일이 발생할 것 같다...

 

 

 

 

 

어제에 이어서 2주차의 마지막이자, 입문주차의 마지막 부분을 학습했다.

 

범위로만 따지면 2.9~ 2.11에 해당하는 부분이라 금방 끝날 것으로 예상하고

오늘 숙련주차를 들어갈까 말까를 생각했었는데,

 

입문주차 마무리를 겨우 할 정도로 빠듯했다.

 

 

2.9 코드 서식 정리하기

에 해당하는 부분은, 이전 과제에서 Prettier 를 간단하게 다루고 넘어갔기 때문에 

어느 정도는 알고있던 부분이다. 

{
    "printWidth": 50,
    "tabWidth": 4,
    "singleQuote": false,
    "trailingComma": "es5",
    "semi" : false,
    "arrowParens": "always"
  }

나름대로 원하는 스타일로 prettierrc.json 을 작성 해 보았다.

singleQuote 부분은 기본적으로 single을 사용할 예정이지만,

한글이 포함되거나 포함될 가능성이 있는 문자열만 "" 을 사용해보려고 한다. (최소한의 개성..?)

물론 변동될 수 있지만 말이다

 

 

 

2.10 배포를 위한 Git 학습 

또한 이전 과제와 그 전에 해당하는 최초의 과제를 진행하며 어느정도 학습한 부분이 있다.

다만, 이전에는 Github Desktop 라는 최신식(?) 사용자 친화적 인터페이스를 갖는 보조도구를 사용했기에

이번에는 강의에 나온 것 처럼 터미널을 이용하여 Git 과 연동하는 작업을 해 보았다.

 

 

 

Github desktop가 알아서 처리해줬던 부분인,

Git 명령어를 먼저 알아보았다.

 

 

 

 

간단하게, 이미 알고있던 desktop 의 방식과 비교하며 정리해볼까? 

 

 

git init 은 현재 위치한 경로를 git repository로 지정하는 명령어 이다.

GUI 에서는 create new repository를 통해 init 기능을 사용할 수 있다. 

(디렉토리를 지정하여 새로운 레포지토리 생성)

아마 Add local repository도 비슷한 기능인듯 하다.

오히려 이쪽에 가까울지도?

 

변경 사항을 스테이징 영역에 올리는 명령어로..

이 부분은 아마 Github desktop를 이용한다면 스킵되어버리는 명령어로 확인이 되어진다.

뭔가 생소한 기능인것 같아서 검색을 해보니, Github desktop 에서는 commit 과 동시에 add가 이루어진다 

라고 설명하는 경우가 많다.

 

개인적으로는 gui의 인터페이스에서

레포지토리로 지정한 폴더의 모든 파일이 자동으로 add 된다는 느낌이긴 한데 맞을지 모르겠다.

(일단 모든 파일이 add 되고, 커밋을 할지 ignore 할지 결정하는 느낌?)

 

 

 

깃의 대표적인 기능중 하나로, 변경사항을 기록하는 것이다.

이 시점으로 얼마나 내용이 수정되었는지, 등록이 되기 때문에 

원한다면 등록했던 많은 커밋 중 하나의 시점으로 파일을 복원하는것이 가능하며,

추가적으로 코멘트를 달아서 해당 커밋의 내용을 직관적으로 설명할 수 있다.

저지른다

 

 

 

본격적으로 git과 github 를 연결하는 명령어로, 

정확히 말하면 로컬 저장소에 원격 저장소를 추가하는 기능이라고 설명되어있다.

commit, push 한 데이터가 어디로 날아갈지 지정하는 명령어 이다.

 

Github desktop 에서는 첫 레포지토리 생성 후

commit 등 원격 저장소를 필요로하는 작업을 하기 전에 

Publish resository를 통해 지정하게 되어있다.

github desktop 에 로그인된 github 계정에 자동으로 연결된다.

 

 

 

클론으로 repository를 생성한다면, 

클론 할 원격 저장소의 주소가 바로 필요하기 때문에, 시작과 동시에 

입력을 하게 되어있다.

git clone 과 remote add 기능이 합쳐졌다고 보면 될 듯 하다.

 

push 는 commit 한 내용을 본격적으로 원격 레포지토리에 업로드 하는 명령어 이다.

 

GUI 에서는 commit 을 하면, 자동으로 push 를 진행하는 버튼이 활성화 된다.

 

 

 

 

push 가 업로드 라면, pull 은 다운로드 라고 할 수 있다.

원격 저장소에 push된 최신 변경사항들을  로컬 저장소로 가져오는 작업을 말한다.

GUI 에서는 해당 명령을 통해, 아직 적용되지 않은 최신 사항을 체크 할 수 있으며,

있을 경우 pull 버튼이 활성화 되어, 비교 및  적용이 가능하다.

 

 

 

2. 11    AWS 배포하기 

오늘 가장 난해했던 부분이다.

 

이전 강의를 통해 만든 서버를 본격적으로 배포하기 위한 수단으로...

기본 사양의 서버인 EC2 에 해당하는 서버를 1년 동안 무료로 사용할 수 있는

대인배  클라우드 서비스 라고 할 수 있다. (물론 프리티어라도 막쓰면 1년 내에 요금이 나올수도 있다)

 

 

강의에서 알려주고는 있지만, 기본적으로 사용한 만큼의 요금이 발생하는 유료 서비스 이며,

잘못 사용 할 경우 금전적인 문제 또는 정보 유출 등의 문제가 발생할 수 있기 때문에, 

추가적으로 알아보고 조심조심소심소심; 하며 진행했고....

시간을 많이 잡아 먹었다 ! !

 

아무튼간에 회원가입과 EC2 인스턴스의 생성은 마쳤고,

 

 

pm2 를 활용하여 app.js 를 구동하는것도 성공했다.

 

웹 브라우저로 접근했을때도 정상적으로 작동하는 모습 !!

위에 보이는 5252 는, 같은 조원이 해당 페이지에 접속해서 남긴 글이다. 

다른 사람도 접근이 가능한것을 확인 !

 

 

pm2 log를 통해 로그도 정상적으로 확인 가능하다.

 

 

여기까지 봤으면 그래도 오늘 할 일은 다 한듯 하다..

 

 

 

 

상당히 골치아픈 문제가 나와서 글로 작성해 보았다.

이게 level 1 이라니...

 

얼핏보면 수월하게 풀 수 있을것 같은 문제지만 (그렇게 생각했었는데요...)

제한 사항을 보면 X와 Y의 길이가 최대 300만 으로 정해져 있으며,

이로 인해서 이중 for문 등을 사용하면 시간복잡도가 급증해 시간초과의 결과가 나오게 된다.

 

 

풀이 설계

 

1. X 와 Y 를 내림차 정렬을 한다.

2. X 와 Y를 맨 앞에서부터 비교하여 같을 경우 answer 에 추가

3. X[0] Y[0] 이 같지 않을 경우 둘 중 작은 값의 다음 index를 검사

4. "0" 의 결과와 "-1" 의 결과를 따로 리턴

 

늘 그렇지만, 이번에도 대단히 효율적이진 않을것 같은 풀이 방향이다.

내림차 정렬을 위한 sort 2회, X와 Y의 값을 비교하기 위한 반복문이 기본적으로 필요하기 때문.

 

 

풀이 시작

 

    X= [...X].sort((a,b) => b-a)
    Y= [...Y].sort((a,b) => b-a)

시작은 역순정렬 부터 한다. 큰 값으로 정렬하여 비교하면 유리할 거라는 생각이었으나,

사실, sort 과정 자체가 시간복잡도를 많이 잡아먹어버린다.

어쨌든 그렇게 설계했기 때문에 이렇게 시작해 보도록 하자.

 

이 과정에서 저번 알고리즘 때 배웠던 [...str] 을 이용한 배열화를 사용해 보았다.

 

그 후, X와 Y를 비교하기 위해 반복문을 사용해야 하는데, 

while 문을 사용하기로 했다. 

 

    let i = 0;
    let j = 0;
    while ( X.length > i && Y.length > j) {
        if ( X[i] === Y[j]) {
            answer += X[i]
            j++ 
            i++
        }

X 와 Y의 끝까지 비교를 해야할 것으로 예상되기 때문에, 위 같이 조건을 주었고,

가장 중요한 X[i] ===Y[j] 일 경우 answer에 추가하는 것 까지는 어렵지 않게 진행되었다.

 

 

잘못된 풀이..?

그 전에, 잠깐 뻘짓을 했던 과정을 살펴보자면

    while ( X.length > i && Y.length > j) {
        if ( X[0] === Y[0]) {
            answer += X[0]
            X= X.substring(1)
            Y= Y.substring(1)
        }

위처럼 동일한 조건으로 진행하지만, i j 를 통해 다음 index로 넘어가는것이 아니라,

.substirng(1) 을 통해  X,Y의 0번의 index만 검사하도록 진행해 보려는 시도를 했었는데, 

굳이 substring 이라는 메서드가 사용된다는 점 때문에 폐기 되었다.

 

시도했던 이유와 폐기한 이유??

 

substring 은 문자열의 0번째 ~를 제거하는 메서드이다. 

참조형이 아닌 기본형 타입의 string을 변조하는건 시간복잡도가 1회 일 것으로 예상을 했었으나,

기본적으로 substring() 의 시간 복잡도는 O(n) 에 해당했다.

글 마무리에 substring을 사용했을 때와, index 순번을 사용했을 때의 시간차이를 비교해보도록 하겠다.

 

 

자, 다시 풀이로 돌아와서, 이제 X[i] 와 Y[j] 가 다른 값일 경우만 처리하면 된다.

 

생각이 닿기는 좀 시간이 걸렸지만,

    while ( X.length > i && Y.length > j) {
        if ( X[i] === Y[j]) {
            answer += X[i]
            j++ 
            i++
        } else if (X[i] > Y[j]){
            i++          
        } else { 
            j++}
        
    }

X[i] 와 Y[j] 의  둘 중 큰 값을 비교해서 

큰 값을 가진쪽의 index 를++ 해서  다음 index를 참조하게 하면,

점점 값이 작아지며 서로 같은 값이 나올때 까지 넘어가게 된다.

 

마무리로, 

    if (answer[0] === "0" ) { return "0"}
    return answer === ""? "-1" : answer

"000000" 만 나온 경우와  일치하는값이 하나도 없을경우만 따로 빼주면 정답이 완성된다.

 

답 코드

function solution(X, Y) {
    var answer = '';
    
    X= [...X].sort((a,b) => b-a)
    Y= [...Y].sort((a,b) => b-a)
    let i = 0;
    let j = 0;
    while ( X.length > i && Y.length > j) {
        if ( X[i] === Y[j]) {
            answer += X[i]
            j++ 
            i++
        } else if (X[i] > Y[j]){
            i++          
        } else { 
            j++}
        
    }
    if (answer[0] === "0" ) { return "0"}
    return answer === ""? "-1" : answer
}

 앞서 말한것 처럼, sort와 반복문이 사용되며 결론적으로 그렇게 효율적인 코드는 아니게 되었다.

 

딱 봐도  11~ 15번 case 가 헬 구간 ( X,Y length가 길게 주어지는듯)

 

 

 

 

 

그렇다면, substirng 의 경우 얼마나 차이가 날까?

function solution(X, Y) {
    var answer = '';
    
    X= [...X].sort((a,b) => b-a).join('')
    Y= [...Y].sort((a,b) => b-a).join('')
    while ( X.length > 0 && Y.length > 0) {
        if ( X[0] === Y[0]) {
            answer += X[0]
            X= X.substring(1)
            Y= Y.substring(1)
        } else if (X[0] > Y[0]){
            X= X.substring(1)       
        } else {
            Y= Y.substring(1)}
        
    }
    if (answer[0] === "0" ) { return "0"}
    return answer === ""? "-1" : answer
}

.substirng(1) 이기 때문에 별로 차이가 없지 않을까 하는 생각에서 완성을 해 보았다.

 

 

유의미한 차이가 있다.

substirng(1) 이라고 해도 결코 상수의 처리시간이 걸리는건 아닌것으로 보인다.

물론 X 와 Y를 추가로 join 해주는 과정에서도 추가적인 시간이 소요됐겠지만 말이다.

 

대충 정리를 하자면 

11~15번 케이스에서 걸린 시간은 

기본 답 코드 ( X[i] Y[j] 로 비교) = 약 2300ms 가량 

두 번째 테스트 ( 기본 답 코드에서 X,Y를 join만 해준 경우)  = 약 2500ms 가량 (join에 걸리는 시간 대략적으로 확인)

세 번째 테스트 ( join 이후 substring을 통해 X[0] Y[0] 으로 비교) =  약 2800ms 가량 ( join과 substring에 걸리는 시간 확인)

 

 

당연히~~~~~

X[i] Y[j] 로 비교하는것이 빠르겠지만, 순전히 궁금증이 생겨나서 

테스트를 해 보게 되었다.

결론은.... 애초에 sort 가 제일 오래 걸리는듯 함 (ㅠ)

 

 

 

물리 계층은 OSI의 7 계층 중 가장 아래에 위치한 1계층으로, 하드웨어로 표현된다.

 

네트워크 장치의 전기적, 기계적 속성 및 전송수단을 정의한다고 할 수 있다.

 

 

전기 신호 하면 가장 먼저 떠오르는 0 과 1 을 이용한 통신이 여기에 해당한다.

 

물리 계층 장비

허브 Hub

전기 신호를 증폭시켜서 연결된 장치간의 통신을 가능하게 해준다.

흔히 말하는 랜선이 허브에 해당된다.

허브는 중계기 역할을 하며, 하나의 장치가 허브로 연결된 모든 장치에게 데이터를 전달하고

이것을 브로드 캐스팅 Broad - casting 이라고 한다.

 

이 방식은 여러 장치가 허브로 연결된 상태에서 1:1 통신이라기 보다는

1: 모든 장치로 통신 데이터를 전송하여 송신 대상만 데이터를 처리하고 

나머지는 데이터가 무시된다고 설명되어있다.

 

리피터 Repeater 

신호의 세기를 증포해서 먼거리의 통신을 가능하게 해주는 장치

 

 

 

물리 계층과 물리 계층 간의 통신은 전기, 빛 , 전파를 통해 통신을 하며 

이러한 것들을 Signaling 이라고 한다.

 

전기

UTP, 전화선, 동축 케이블이 해당

 

광섬유 케이블 (빛의 패턴)

 

전파

wi-fi 와 같은 무선인터넷 (마이크로파 패턴을 신호로 사용)

 

전송 단위

 

Signaling의 방식은 위처럼 다양하지만, 어찌됐던 물리 계층이기 때문에

이 모두는 전기 신호인 0, 1 로 데이터를 인코딩해서 전송한다.

 

 

 

 

 

본문에 앞서서,

오늘은 월요일임에도 불구하고 컨디션이 나쁘지 않았는데

알고리즘 풀이도 뜻대로 되지 않고,

강의는 여전히 새로 접하는 내용의 정의와 활용의 반복으로 이루어졌기 때문에

정신력의 소모가 상당했다...

(하늘에서 정의가 빗발친다...)

 

오늘 학습한 내용은, Node.js 입문주차 2주차에 해당하는 내용이며,

 

영상의 길이만 1주차의 4시간을 뛰어넘은 6시간인 데다가 , 앞서 서술한 내용처럼 

학습이 원활하게 흘러가지 않았기 때문에 전부 듣지 못했다.

2-8 에 해당하는 내용인 Joi 활용에 대한 부분 까지만 학습했다.

 

 

1. MongoDB

강의의 시작은 MongoDB 의 활용이었다.

첫 과제때 잠깐이나마 활용했던 Firebase 처럼, 비관계성 데이터 베이스중 하나로,

이번 강의에서는 MonghDB 를 통해 database 를 구축하고 실습을 진행하게 된다.

 

추가로 Studio 3T 라는 GUI 툴을 활용해 MongoDB의 관리를 용이하게 할 수 있다.

 

그리고 또...

mongoose 라는 라이브러리를 통해

JavaScript 에서 MongoDB에 데이터를 쉽게 읽고 쓰게 해주는 ODM (Object Document Mapper) 도 활용한다.

 

 

2. 할 일 메모 사이트 설계

해당 주차의 메인 실습 내용에 해당하며,

앞서 배웠던 Express를 통해 서버를 열고, MongoDB와 연결하여,

서버가 종료되더라도 데이터가 저장되어 연속성을 보장할 수 있는 환경을 구축하며

 각종 모듈과 미들웨어를 통해 원하는 기능을 구현하는 학습이 진행되었다.

 

배우는 내용이 딱딱하니 TIL도 딱딱할 수 밖에 없는건가...

 

 

Studio 3T 를 통해 DB의 상태를 확인할 수 있다.

 

그런데 할 일 메모 사이트에 해당하는 DB가 보이질 않는다...

어디간거지? mongodb_prac ...은 아닌데...?   DB이름도 가물가물가물치

 

 

index.js 를 확인해보니, 분명 dbName 을 todo_memo 로 지정했고, 

 

데이터도 정상적으로 추가가 되고, get 으로도 확인이 가능한데 db가 없어..?

 

유령 데이터 베이스 ㄷㄷ

 

 

해답은 정말 간단했다.

Studio 3T가 보여주는 데이터 베이스는 실시간 또는 데이터 변동이 생기면 알아서 refresh 되는게 아니라

갱신을 해서 새로운 정보를 내놓게 해야한다... 

사실 Studio 3T를 껐다가 켰는데 Refresh 된거라 따로 Refresh 방법을 아직 모르겠다...

 

아.. 아무튼

 

할 일 메모사이트 만들기의 진행 내용은,

 

Express 를 통한 서버 구동, 

post() 를 통한 새로운 데이터 생성,

.findOne()  한 가지의 데이터를 선정

.sort('order')   오름차순 정렬

.sort('-order')    역순 정렬

.exec();  await 를 적용하기 위한 수단

 

.save();   클라이언트에게 반환

 

.get()   데이터베이스 목록 조회

.patch()   데이터의 내용 수정

.delete()  데이터의 삭제

 

추가로 joi를 활용한 유효성 검증 부분  (class 의 setter 와 비슷한 기능인건가..)

validate()   동기로 검증..? 

validateAsync() 비 동기로 유효성 검증

 

try/catch 를 이용해 에러 대응하기

에러 발생시  단순한 에러라도 서버가 내려가버리기 때문에

이런 경우는 try catch 를 통해 에러의 처리를 따로 해주는 작업이 필요하다

 

 

적어놓고 보니까 꽤 많은 메서드가 사용되었는데, 물론 모두 이해했다고 하기는 힘들다.

 

입문 주차가 이 정도면 숙련 주차엔 무엇을 배우게 되는걸까??

 

 

 

이번 과제.. 벌써부터 걱정이 된다.

'내일배움캠프' 카테고리의 다른 글

24.09.05 TIL : Node.js 숙련주차  (0) 2024.09.05
24.09.03 TIL : Node.js 입문주차  (1) 2024.09.03
24.08.30 TIL : Node.js 입문주차  (0) 2024.08.30
[내일배움캠프] 24.08.29 TIL  (0) 2024.08.29
[내일배움캠프] 24.08.28 TIL  (1) 2024.08.28

 

 

오늘,  CH3 에 해당하는 내용이 발제되었다.

 

CH 3 의 주 내용은 주특기로, 

즉 Node.js 를 말한다.

 

 

 

 

 

 

1주차에 포함된 내용

 

무려 영상길이만 총 4시간에 달하며 

 

매 순간마다 새로운 개념과 용어가 등장하는데다가

거의 100% 이론 강의였기 때문에 정신이 급속도로 피폐해졌다...

 

 

내용을 전부 글로 작성하는것은 의미가 없기 때문에

짚고 넘어가야할 부분만 정리해야겠다.

 

 

 

 

브라우저의 통신 방식에 관한 내용이다.

 

user : URL 입력 -> DNS 서버로 전달 -> name을 IP형태로 -> IP에 HTTP로  Request

-> 웹 서버에서 Request 처리-> 처리결과 HTTP Response 를 웹 브라우저에게 전달

-> 웹 브라우저가 HTTP Response를 내용을 바탕으로 user에게 표시

 

 

 

 

 

DNS 는  IP주소 ( 8.8.8.8 )  ==== >   도메인 (google.com) 

형태를 변경해 주는 서비스 이다.

 

기존 8.8.8.8 형태는 IPv4 이고,

2001:db8::ff00:42:8329 같은 형태는 IPv6 로, 보안과 성능이 강화된 버전이다.

 

 

 

Node.js 란? 

사실, 이전 과제가 Node 환경에서 게임을 만드는 과제였기 때문에 

어느정도 머리속에서 정리가 된 상태이다. 그나마 아는 부분이기 때문에 따로 정리하지 않겠다 !

Package Manager 에 관한 내용 또한 마찬가지.

 

 

 

 

 

본격적으로 서버에 관한 강의가 시작되었다.

프레임 워크는 웹 서비스를 빠르게 구현할 수 있도록 도와주는 도구이며, 

밑바닥 부터 서버를 만들어 올리는것도 가능하겠지만, 현실적으로 비효율적이기 때문에

프레임워크를 통해 효율적인 개발하는것이 권장된다.

어디까지나 프레임 워크인 것이지, express 자체가 서버인 것이 아니다.

 

 

 

실습 !?

express.js 를 이용하여 만든 서버를 VScode 툴을 이용해 Node 환경에서 구동하고

Insomnia 를 활용하여 해당 서버주소에 접근하고 요청하는 내용을 Test 하는 과정 

 

????? 이거 맞아?????

 

express.js 프레임워크 설치 

해당 모듈을 참조

 

 

 

express 해줘 !!

 

 

/api/about  내용을 담당하는 goods.js

 

 

 

/api/news  주소에 접근시 리턴하는 내용과

/api/news/:newsId 에 접근 시 리턴하는 내용을 담은 news.js

 

 

해당 주소에 대한 접근 결과와 Headers 에 해당하는 내용을 보여주고

잘 작동하고 있는지 쉽게 알아볼 수 있게 해주는 insomnia 

 

newsId에 임의로 user 가 입력한 값을 server 가 전달 받을 수 있다.

 

그 과정에서 사용되는 .params 부분이 아직 이해가 안 안돼서 복습이 필요할 듯 하다.

 

뿐만아니라 사실 오늘 배운 server 에 대한 내용이 전부 낯설고 

제대로 이해가 안된것 같은 느낌이 든다...

 

function이 뭔지도 모른채로 알고리즘 문제를 처음 접했을 때,

이런 느낌이었던 것 같은데.....?

 

이럴 때에 해결 방법은, 이해 될 때 까지 박치기를 하면 된다 !

 

주말이 사라질 듯 하다.

 

 

이론은... 너무 힘들다 !!

'내일배움캠프' 카테고리의 다른 글

24.09.03 TIL : Node.js 입문주차  (1) 2024.09.03
24.09.02 TIL : Node.js 입문주차  (0) 2024.09.02
[내일배움캠프] 24.08.29 TIL  (0) 2024.08.29
[내일배움캠프] 24.08.28 TIL  (1) 2024.08.28
[내일배움캠프] 24.08.27 TIL  (1) 2024.08.27

+ Recent posts