09/07, ORM, Shortly.mvc

Ian·2020년 9월 7일
1

Today I Learned

목록 보기
20/40
post-thumbnail

Office Hour

DB 문법과 할 줄 알아야 하는 수준에 대해서

작은 회사에 가면, 사실상 풀스택이다. 백을 뽑아도 프론트를 어느정도 해야하고, 거꾸로일 수도 있다. 반대로 큰 회사에 가면 분업을 하여 DB관련 회사가 아니라면 볼 일이 없을 수도 있다. 그러나 그게 아니더라도 "소양" 으로서의 DB 정도는 할 줄 알아야 한다.

DB 선택

SELECT, WildCard 등으로 조회하는 게 가능하면 된다.

첫 번째로 큰 값은 Max(), 그러면 두 번째로 큰 값은?

그려면, "두 번째로" 높은 점수는 어떻게 가지고 올 수 있을까?

Select max(scores) 
from exams where
scores < (select max(scores) from exams);

일단은 가장 무난한 방법인, "최댓값보다 적은 값 중 가장 큰 값 가져오기" 방법이다. Nestsed Query 를 사용한 방법이다.

그리고 저 쿼리문을 통으로 ALIASES 를 통해 사용할 수도 있다

(Select max(scores) 
from exams where
scores < (select max(scores) from exams)) AS getSecond;

왜냐면 저 쿼리 자체가 table 을 만들어서 주는 쿼리이기 때문이다. 테이블에 대한 aliases 문법이 적용가능한 이유.

Depth 가 한 단계, 두 단계인 경우는 이런 식으로 할 줄 알아야 하지만, 더 깊은 경우는 ORM 을 사용하거나, framework 를 사용한다. 굳이 Raw Query 문법에 그렇게 엄청난 depth 를 사용할 필요는 없다.

Schema 설계에 대한 두려움

직접 DB를 설계하고, Schema Best Practice 를 많이 찾아보면서 공부하면 된다. 각 field 마다 어떤 자료형을 사용하는지도 확인해야 한다. indexing 에 대한 유-불리가 있는지를 고려해야 하기 때문이다. 그렇게 하면 나아질 수 있다.

High Scalability -

큰 스케일을 만들고 싶으면, High Scalability 라는 사이트를 활용해서 공부하면 된다. 물론, 지금은 열심히 공부하고 수준을 쌓고 다시 보면 된다. 아직은 어렵다

DB 의 관계 유형

1:1, 1:N, N:M 의 관계. N:M 의 경우는 중간에 JOIN Table 을 넣어준 뒤 1:N 구조를 두 개를 만들어 주는 식으로 치환한다.

JOIN

뭔가 조금... 연습은 해 봐야 할 것 같지만, 솔직히 많이 어렵지 않다면 할 수 있을 거 같다는 생각에 "할 수 있으나, 자신이 없다" 라는 응답을 했다.

SQL 에 대해서

SQL은 하나의 표준이다. 그러나 그 표준을 만드는데 "공통사항" 과 "권고사항" 이 존재하기 때문에, "공통사항" 은 표준대로 무조건 지켜야 하겠지만, "권고사항" 은 구현하는 사람들마다 조금씩 다르기 때문에 DBMS 마다 차이가 있다는 점을 알아두어야 한다.

간단히 말해, 다른 DBMS에서는 되는데, MySQL 같에서는 안 될수도 있고, 그 역의 상황이 발생할 수도 있다는 점이다. 그래서 당황할 필요가 없다

SQL 의 역사

SQL 의 태동과 현재

1970년도에 IBM 엔지니어(2명...!) 들이 만든 SEQUEL(structured english query language)이 SQL의 시작이다. 그러나 그 SEQUEL 은 특허가 있었기 때문에 relational software, 현재의 ORACLE 은 SQL 이라는 상표로 그것을 만든다. 그러다가, 그 SQL이 ISO 에 의해서 산업표준이 된다. 그리고 그렇게 상황을 거쳐서

  • DB2 and Informix Dynamic Server - IBM
  • RDBMS(Oracle) – Oracle (MySQL)
  • SQL Server and Access - Microsoft
  • MySQL, PostgreSQL - Open source

아래와 같은 상황들로 발전하게 된다.

SQL 이 있기 전까지는

File System 을 사용했다. 즉, file 에 직접 read/write 를 했다는 점이다. DB도 물론 FS 를 거치진 않을 수 없다. 그러나, FS보다 더욱 편하게 작업하기 위해 이런저런 공정들을 거쳐주고, 더욱 추상화를 시켰다는 차이점이 있다.

File System 의 단점은 이런것들이 있다.

  1. Data redundancy

  2. Data inconsistency

  3. Difficult data access

  4. Security problems (unauthorized access)

  5. Difficult concurrent access

Typically, in a file-based system, when an application opens a file, that file is locked

그리고 세상(의 정보)를 entity - entity 와의 "관계"를 통해 보는 그 관점이 잘 먹혀서 지금도 SQL 이 잘 사용되고 있다.

Structured VS UnStructured

지금은 또 새로운 패러다임이 등장했다. 꼭 Structured 가 구조가 아닌, UnStructured 스타일도 나오고, 그 중간점 쯤 되는 Semi-Structured 라는 스타일도 나왔다. 스케일이 커지니까 꼭 Schema 를 통해서 관리해서는 안 된다. 이런 것들을 NoSQL 이라고 한다. NoSQL 의 대표주자는 점유율 기준으로는 MongoDB.

그런데 위에서 말 한대로 서비스를 크게 하는 회사들은 DB를 한 종류에만 쓰지 않는다. 특정 부분에 강점을 보이는 DB들이 존재하기 때문에 취사선택을 한다.

No-SQL
key-value stores: Redis, Amazon Dynamo DB
column stores: HBase, Cassandra
document stores: Mongo DB
graph databases: Neo4J
search engines: Solr, ElasticSearch, SplunkMERN

SQL 과 NoSQL 의 차이

Consensus (전파) 가 Strict 한 대신 빠른 MySQL, Consensus 가 Strict 하지 않은 대신 약간은 딜레이가 있는 NoSQL. 전자는 무조건 DB상의 갱신이 발생하면 그 갱신결과를 빠르게 전파해야하는 은행, 항공기좌석예약 시스템 등에서 사용할 것이고, 후자는 그렇게 빠르게 전파할 필요는 없는 다른 서비스에서

AWS

Ec2, s3, DB(dynamoDB, aurora, sql)cloudfrontauto-scaling), lambda, Docker (ecs)

별의 별 게 다 있다... 이 정도만 쓸 줄 알아도 정말! 정말! 도움된다

그리고 프로젝트 할 때 MongoDB 도 도전해보시길

질문

스키마를 효율적으로 구성한다 라고 정의할 수 있는 것들이 있을까요? 예를들면 동일한 데이터(text)는 1회만 존재해야한다... 등등
있다면 찾아볼 수 있는 키워드들은 어떻게 될까요

정규화를 찾아봐라


MVC Design Pattern

MVC 란 무엇인가?

코드의 구조를 하나에 통으로 쓰는 게 아니라, model - view - controller 로 기능을 분할해 놓는 행위를(Design Pattern) 의미한다. 어떻게 보면 옷장에 속옷 / 겉옷 등을 마구잡이로 박아놓는 게 아니라, 속옷은 속옷을 놓는 곳에, 겉옷은 겉옷을 놓는 곳에 정리정돈해서, 꺼내기가 쉽게끔 하는 행위와 비슷하다고 할 수 있다.

이런 MVC 컨셉은 Ruby, Express, Angular, Flask 등에서 많이 사용한다.

Model

Data를 가지고 있거나, DB와 연결이 되어있어서 DB로부터 데이터를 참조하는 형식이다.

View

유저가 보는 화면을 그려내는 부분이다. 웹의 경우는 HTML/CSS 로 작성된 작업물들이 속한다. 그저 그려낼 뿐이다.

Controller

view 에서 일어나는 action 을 비롯한 Input value 를 받아 가공하고, model 로 넘겨준다. 거꾸로 model 에서 view 에 data 를 데이터를 반환해주는 경우, controller 가 이해하기 쉽게 가공을 거친 뒤 view section 으로 넘겨준다.

장점

  • 코드 가독성을 올려주어서 협업에 용이하다
  • 서비스의 스케일을 키우고 줄이는데 용이하다

다 기능에 따라 나누어진, 구조화된 덕분에 가능한 일


ORM

what is ORM?

Object-Relational-Mapping 의 약자, Realtional Database 에 접근할 때, JS 의 객체를 사용할 때처럼 접근할 수 있게 해주는 역할을 한다.

Realtional DB 와 Object

우리가 Obejct 를 생성하고 수정하고 접근하는 과정은 RDB 에서 table, column 등에 치환해서 생각해 볼 수 있으나, 둘의 문법은 다르다. 그래서, ORM이라는 것이 등장했다. ORM 은 JS 코드에 익숙하고 RDBMS 의 코드에는 익숙하지 않은 사람들이 JS 의 OOP 와 같이 RDBMS 를 사용할 수 있게끔 하는, 일종의 "번역기" 같은 역할을 한다.

ORM 의 장점

  1. DB 문법에 익숙하지 않아도 ORM 을 익혀 ORM 으로 접근가능하다.
  2. JS-SQL 의 각자다른 문법을 사용하는 코드가 따로 존재하는 것이 아니라, 일관된 형태의 문법으로 코드를 작성하기 때문에 가독성이 올라간다. (JS 코드처럼 DB를 운용할 수 있으니까)

오늘 사용할 ORM - Sequelize

ORM 의 일종으로, 다양한 RDBMS 를 지원한다. (Postgres, MySQL, MariaDB 등등). 그래서 SQL 이라는 표준에 각자 조금씩 다르게 구현한 RDBMS 의 미묘한 차이를 ORM 을 사용한다면 크게 신경써주지 않아도 된다. 물론 ORM 이 존재하더라도, JOIN 과도 같은 "개념" 은 우리가 이해해야 적절하게 사용할 수 있기 때문에 SQL 문법에 어느정도 익숙해져야 한다.

sequelize

자세한 사용방법은 Sequelize 의 문서를 참조하면서 알아보자.

간략하게 적어보는 Sequelize 의 특성

  • PRIMARY KEY 로 이용하는 id , 생성일시나 변경일시를 작성하는 created_at, updated_at 등을 기본적으로 지원한다 → 그렇기에 별도로 ORM 코드에 명시해줄 필요는 없다.
    • 만약 자동으로 생성되는 위의 것들이 내가 필요가 없는 경우 어떻게 자동생성시키지 않을지 등도 공식문서를 꼭 읽어보고 확인하자.
  • Promise 기반이기 때문에, .then 을 사용해 체이닝을 할 수 있다. → 비동기이기 때문에 async 도 가능할지 확인해보고 싶다.

더 공부했으면 하는 부분들

Association

사전적 의미는 "연관을 짓는 행위". SQL 의 JOIN 과 관련이 있다. 실무에서 JOIN 을 흔하게 사용하기 때문에 ORM 을 통해 table JOIN 을 해 보자! (공식문서의 association 항목에서 참조 가능)

Transaction

은행 업무를 떠올려보자. 그 중에서 송금해야 되는 내용을 query 로 날린다고 생각해보자. 그 송금 query 는 통장에서의 조회 / 통장에서의 출금 / 다른 통장으로서의 입금 이라는 과정이 섞였을 것이다. 그런데, 내 통장에서의 조회와 출금은 잘 되었는데 DB에 오류가 생겨서 다른 통장으로 입금이 되지 않았다면 굉장히 곤란한 상황일 것이다. 그 때 우리는 rollback 을 하게 되고, 다시 시도해서 성공했을 때 성공하면 commit 을 한다

→ ...라고만 하셨는데, 뭔지는 공식문서를 보고 확실히 정리하자.


Short.ly mvc

이번 스프린트는?

위에서 알게 된 Sequelize 라는 ORM 을 이용하여 테이블을 만들고, request 와 그에 수반되는 SQL query 또한 ORM 으로 디자인해보는 스프린트이다. 거기에, MVC 패턴으로 기능별로 코드를 분할해 정리한다.

Getting start - ORM Setting

Sequelize

공식 홈페이지를 기반으로 ORM 을 설치한다.

Sequelize

sequelize migration 또한 같이 설치한다.

Just like you use version control systems such as Git to manage changes in your source code, you can use migrations to keep track of changes to the database. With migrations you can transfer your existing database into another state and vice versa: Those state transitions are saved in migration files, which describe how to get to the new state and how to revert the changes in order to get back to the old state.

migration 단락에서 소개하는 부분을 읽어봤는데, 우리가 git 을 통해 버전 관리를 하는 것처럼 DB 에서도 버전의 변화 등을 기록하는 걸 migration 을 통해 할 수 있다고 한다.

migration bootstraping with sequelize-cli command

init 을 이용해서 migration 관련 세팅을 한 큐에 진행할 수 있다. 마치 npx react create-react-app 과도 같은 느낌. bootstraping 이란 단어도 처음 봐서 검색해봤는데, 위키에서 그 의미를 잘 설명해줘서 밑에 적어보았다. 아, bootstrapping 은 해당 명령어를 터미널에 입력하면 할 수 있다.

npx sequelize-cli init

그렇게 하면 config, migrations, models, seeders 라는 폴더들이 만들어진다.

각 폴더들의 역할을 적어보자면, 이러하다

confing : "CLI 에게 어떻게 DB와 연결하라" 라는 config 파일들을 저장하는 폴더

models : 내 project 의 모든 model 들을 저장하는 폴더

migrations : 모든 migration 파일들을 저장하는 폴더

seeders : 모든 seed 파일들을 저장하는 폴더

check config file

{
  "development": {
    "username": "root",
    "password": null,
    "database": "database_development",
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  "test": {
    "username": "root",
    "password": null,
    "database": "database_test",
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  "production": {
    "username": "root",
    "password": null,
    "database": "database_production",
    "host": "127.0.0.1",
    "dialect": "mysql"
  }
}

config 폴더의 config 파일을 여니 이런 JSON 이 있었다. 기본적으로 MySQL 을 사용하는데, 다른 DBMS 를 사용한다면 저 dialect 에다가 입력하라고 한다. development , test, production 의 key 는 model/index.js 에서 process.env.NODE_ENV 와 matching 하는 데 사용한다고 한다. 만약 NODE_ENV 라는 환경변수가 딱히 지정되어있지 않으면, development 를 기준으로 시작한다고 한다. 포트번호는 각 RDBMS 의 기본 포트넘버를 사용한다고 하는데, 별도로 지정해 주고 싶으면 port 라는 key 를 만들고, 포트번호를 그 안에 value 로 적어주면 된다고 한다.

 "development": {
    "username": "root",
    "password": null,
    "database": "database_development",
    "host": "127.0.0.1",
    "dialect": "mysql",
		"port" : 8080
  }

이런 식으로

Creating the first model and Migration

위의 과정으로 Migration 을 할 수 있는 과정도 다 끝났다. migration 또한 간단한 command 로 실행할 수 있다. 이번에는 model:generate 명령어를 사용할 건데, 이 명령에는 두 가지 Option 을 필요로 한다.

  1. name : 모델의 이름
  2. attribute : model attribute 의 목록

예시로, User 라는 model 을 만들어보자

npx sequelize-cli model:generate --name User --attributes firstName:string,lastName:string,email:string

이렇게 해서 우리는 User 라는 이름의 model file 을 users 폴더에 만들어 넣었다. 동시에 20200907071556-create-user.js 라는 이름의 migration file 도 migrations 이라는 폴더에 집어넣었다.

Running Migrations

이제 DB에 직접 어떤 값을 추가해보자. 그러려면 먼저 db:migrate 라는 명령어를 통해서 migration 을 해 주어야 한다.

npx sequelize-cli db:migrate

그렇지만 해당 명령어를 통해 실행해봤더니, Please install mysql2 package manually 라는 에러메시지와 함께 실행이 되지 않았다. 그래서 구글링을 해 본 결과, stackoverflow 에서 나오기를, 그냥 설치하란다. 설치하기 전, package.json 파일을 확인해 봤는데 mysql2 가 이미 dependencies 에 있었다.

생각해보니 해당 스프린트를 시작할 때 npm install 을 하지 않았다는 사실을 뒤늦게 알게 되었다....

ERROR: Please install mysql2 package manually

dotenv

그래서 설치해보았다. 이번에는 내가 sql 계정의 비밀번호를 걸어놓고 config 파일은 바꾸지 않아서 잘 되지 않았다. 그래서 dotenv 를 활용해 환경변수를 잡기로 했다. 물론 exports 같은 것도 있지만, 내가 지금 사용하고 있는 터미널이 죽으면 또 해 줘야 하기 때문에 이걸 사용해서... 인데 생각해보니 그냥 config.json 안에 비밀번호를 입력하고 그걸 통째로 .gitignore 에 추가하면 되어서 그냥 npm install —save dotenv 정도만 해 놨다. 이번에도 시도해보았지만, Unknown Database 가 나오길래 구글링 해 봤더니, sequelize db:create 를 입력해서 해결하면 된다고 한다.

unhandled rejection sequelizeconnectionerror: unknown database

여튼, 그렇게 해서 해당 명령어를 실행할 수 있었고, migration 을 위해서는 npx sequelize-cli db:migrate 를 활용하면 된다는 걸 알았다. migration 을 되돌릭 위해서는 npx sequelize-cli db:migrate:undo 를 실행해 주면 된다. 특정 시점으로 migration 을 하고싶다면 npx sequelize-cli db:migrate:undo:all --to XXXXXXXXXXXXXX-create-posts.js 와 같이 migration file 을--to 라는 option 으로 넣어주면 된다.

Seed 파일 만들기

seeder 를 통해 우리가 만든 모든 migration data 를 관리할 수 있다. seed 파일은 데이터에서의 변화들인데, 이걸 통해서 sample data 혹은 test data 등으로 만들 수 있다. npx sequelize-cli seed:generate --name demo-user 라는 명령어를 통해서 demo-user 라는 이름의 seed 를 만들어보자. 이렇게 하면 seeders 라는 폴더가 생기고, XXXXXXXXXXXXXX-demo-user.js 라는 우리가 아까 지정해 준 demo-user 라는 이름을 달아놓은 seed 가 생긴다. 그리고 그 파일에 들어가서, 공식문서에서 나온대로 수정을 한 번 해보자.

module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.bulkInsert('Users', [{
      firstName: 'John',
      lastName: 'Doe',
      email: 'example@example.com',
      createdAt: new Date(),
      updatedAt: new Date()
    }]);
  },
  down: (queryInterface, Sequelize) => {
    return queryInterface.bulkDelete('Users', null, {});
  }
};

Seed 파일 실행

npx sequelize-cli db:seed:all

라는 명령어를 통해 seeder file 을 실행할 수 있다.

라는 과정들을 해 봤는데, 솔직히 조금 어렵다. 해 보면서 알아가야 할 듯 하다. 대략 migration 이라는 게 무엇인지, 그리고 migration 을 통해 어떤 걸 할 수 있는지를 알 수 있게 되었다. NODE_ENV 라는 환경변수에 맞추어 구동되기 떄문에 export NODE_ENV="production" 등으로 값을 할당해주면 그 값에 맞추어 DB의 작업환경이 바뀌고(어떻게 보면 git 의 branch 같다), 그리고 DB가 없다면 db:create 로 만들어주고, model:generate 를 통해 초기 model 을 생성해주고, 그렇게 버전관리를 하라는 거 같다. 버전관리는 잘 아직 어떻게 써야할지 와닿지가 않아서 진짜 해보면서 알아가야 할 거 같다는 생각이 든다.

질문에 답해보기

  1. 기본적으로는 어떤 환경? : development
  2. 환경 전환은 어떻게? : process.env.NODE_ENV 를 따라가기 때문에, export NODE_ENV="test" 등으로 환경변수를 생성(혹은, 재할당)하여 바꾸어주면 된다.
  3. 여러개의 환경이 분리되어있는 이유는? : git 의 branch 같은 개념이고, 용도도 비슷하다고 이해하고 있다. version control 을 할 수 있게끔 하는 기능이고, 해당 migration 이라는 기능은 branch 를 나누어 용도별로 따로 작업하는 과정이라고 추론하고있다.
  4. [optional] 설정 파일이 .gitignore 에 등록되어있는데, 설정파일을 git 의 관리를 받게 하는 대신, 환경변수를 사용하게 만들 수 있는가? : "json using .env" 이라는 키워드로 구를링을 해 보니 누가 방법을 적어놓았는데, 쉬워보이진 않는다. 그리고 optional 이기 때문에 요구하는 spec 에 맞춰 테스트를 통과시키는 게 우선일 듯 하다(시간은 한정되어있으니까) 그래서 나중에 해 보려고 한다.

Injecting Environment Variables into JSON Files

Getting Startted - 모델 생성

cli 를 통해 모델을 만들기... 는 위에서 한 것대로 하면 될 듯 하다. 모델의 이름은 url, 모델의 요구사항은 url, title, visits. 위에서 만든 User.js 라는 파일을 수정하였다. migration 파일도 sequelize-cli command 를 통해 처음에 파일들을 수정하였다. 추가로 필요한 migration 이 있는 경우, migration skeleton 및 sequelizer query 양식에 맞추어 작성해봐야겠다.

질문에 답해보기

Sequelize

  1. MySQL 의 varchar 나 int 타입은 Sequelize 에서 어떤 형태로 정의되어야 하나요? → 해당 링크를 통해서 이야기하자면, Sequelize.STRINGSequelize.INTEGER 의 형태로 정의해야 한다.
  2. 왜 Sequelize 의 타입 정의와 MySQL 의 타입 정의가 다를까요? → 다양한 RDBMS 를 dialects 라는 것으로 지원하기 때문에, MySQL 에다가만 맞출 수는 없으니까(추측)
  3. 마이그레이션을 해야 할 때 주의할 점은? → up / down 에 어떤게 들어갈지 잘 생각해야 한다는 점(?)

오늘은 뭔가 공식문서를 읽는데 시간을 참 많이 할애한 거 같다. 테스트 케이스 큰 것 두 개 중에서 한 개를 겨우 끝낼 수 있었다. 내일은 이제 이렇게 물린 DB 와 함께 MVC 패턴대로 url shortner 를 구현해보아야 겠다. 오늘의 공부는 여기서 마무리...


기타 등등

세상의 여러가지 모습들을 프로그래밍 개념으로 치환해서 생각하면 좋다. DB도 마찬가지로 그렇게 생각해보자. 식당에 간다면 손님과 메뉴를 테이블로 만든다면, Schema 를 어떻게 만들 수 있을까? 등등.

NAVER D2

민철 엔지니어님께서 추천해 준 블로그의 포스팅, "백엔드 개발자를 꿈꾸는 학생개발자에게"


Nested Concepts

Bootstrapping

Bootstrapping

In computer technology the term (usually shortened to booting) usually refers to the process of loading the basic software.

컴퓨터 과학에서의 해당 의미는 기초적인 software 를 로딩하는 과정을 의미한다고 한다. 즉, 작업환경 설치.

profile
правда и красота, truth and beauty

0개의 댓글