일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- Algorithm
- JavaScript
- Django
- 파이썬 웹프로그래밍 장고
- 독립영화플랫폼
- 장고
- 자바스크립트
- 장고 개발 순서
- 예술영화추천
- 북마크앱
- join()
- 장고 프로젝트 순서
- mongodb
- 프로젝트
- Exercism
- 개발
- 장고 프로젝트
- 타사인증
- Django Blog
- Bookmark
- 알고리즘
- MyPick31
- passport.js
- 북마크만들기
- til
- MYSQL
- python
- Node.js
- ART_Cinema
- Blog
- Today
- Total
Juni_Dev_log
(node.js) [Part.7] 익스프레스 프로젝트를 모듈화하기 - 모듈화 방법 자세히 살펴보기 본문
(node.js) [Part.7] 익스프레스 프로젝트를 모듈화하기 - 모듈화 방법 자세히 살펴보기
Juni_K 2021. 1. 21. 15:06지금까지 만든 사용자 기능이나 데이터베이스 저장 기능은 모두 하나의 app.js 파일에 들어있다.
따라서 기능이 많아질수록 하나의 파일에 들어가는 코드의 양도 많아진다. 결국 코드를 분석하기 어려워진다.
이 문제를 해결하려면 기능별로 코드를 구분한 후 독립된 파일로 분리시키는 것이 좋다.
이렇게 별도의 파일로 분리하는 것을 모듈이라고 한다.
익스프레스로 웹 서버를 만드는 과정에서 이미 모듈에 대해서 이미 알아보았다. 이 모듈은 구성 방법에 따라 몇 가지 전형적인 코드 패턴을 갖는다. 여기에서는 모듈을 더 자세히 알아본 후 DatabaseExample 프로젝트의 app5.js 파일에서 구현한 각 기능을 모듈로 분리하여 구성해보자.
다양한 방법으로 모듈 만들기
가장 기본적인 모듈 사용 방법은 자바스크립트 파일을 새로 만드는 것부터 출발한다. 그리고 그 파일안에서 exports 전역 변수를 사용한다.
exports 전역 변수는 어디에서나 접근할 수 있게 정의된 것이고 속성도 추가할 수 있다.
즉, 새로운 파일을 만들고 그 안에서 exports 전역 변수에 속성을 추가하면 다른 파일에서도 exports 전역 변수의 속성을 참조할 수 있다.
예를 들어, 사용자 정보를 확인하려고 만든 기능을 별도의 user1.js 자바스크립트 파일로 분리한 후 모듈로 구성하려면 getUser() 함수와 group 객체를 exports 의 속성으로 추가해야한다. 이렇게 만든 모듈은 module_test1.js 처럼 이 모듈을 사용할 파일에서 require() 메소드로 불러들일 수 있다.
require() 메소드로 불러들인 모듈을 변수에 할당하면 그 변수에는 exports 가 속성으로 할당된다.
따라서, 속성이 할당된 변수에서는 exports에 추가한 getUser() 함수나 group 객체를 참조하여 사용할 수 있다.
위와 같은 구조를 만들기 위해 먼저 새로운 익스프레스 프로젝트 ModuleExample 을 만든다. 프로젝트 안에는 user1.js 파일과 module_test1.js 파일을 새로 만들어 추가한다.
user1.js 파일에 들어가서 코드를 작성한다.
1
2
3
4
5
6
7
8
|
// exports 객체 속성으로 함수 추가
exports.getUser = function(){
return {id : 'test01', name : '소녀시대'}
}
// exports 객체 속성으로 객체 추가
exports.group = {id : 'group01', name : '친구'};
|
cs |
exports 속성 두 개가 추가되었다. 첫 번째 속성은 getUser 속성이며 속성의 값으로 함수가 할당되었다.
이 함수는 id 와 name 속성을 가진 객체를 반환하는데, 사용자 정보를 객체로 반환받아 확인하려고 만든 함수이다.
두 번째 속성은 group 속성이며 id 와 name 속성을 가진 객체가 할당되었다.
이것은 그룹의 아이디와 이름을 알 수 있도록 만든 객체이다. 이렇게 만든 모듈 파일은 module_test1.js 파일에는 다음과 같이 입력한다.
1
2
3
4
5
6
7
8
|
// require() 메소드는 exports 객체를 반환함.
var user1 = require('./user1');
function showUser() {
return user1.getUser().name + ', ' + user1.group.name;
}
console.log('사용자 정보 : %s', showUser());
|
cs |
user1.js 파일로 만든 모듈을 사용하기 위해 require() 메소드를 호출한다. require() 메소드로 불러들인 모듈은 user1 변수에 할당한다. require() 메소드는 exports 객체를 반환하기 때문에 user1 변수는 exports 객체를 참조한다.
이제 user1 변수는 exports 객체와 같다고 볼 수 있으므로 user1 변수에 들어있는 getUser() 함수를 호출한다. showUser() 함수는 콘솔 창에 로그를 출력하는 간단한 기능을 수행한다.
showUser() 함수 안에 들어있는 코드는 user 변수의 getUser() 메소드를 호출하여 반환받은 객체의 name 속성을 참조하여 사용자의 이름을 알아낸다.
그리고 group 객체의 name 속성을 참조하여 그룹 이름을 알아낸 후 문자열을 반환한다.
module.test1.js 를 실행해보면 결과를 알 수 있다.
이 결과는 user1 변수가 exports 객체를 참조하여 출력한 것이다.
exports 에 객체 지정하기
user1.js 파일에서 exports 객체의 속성으로 getUser() 함수와 group 객체를 추가했으니 exports 에 객체를 만들어 할당할 수도 있다.
exports 에 객체를 할당할 수 있는지 확인해보기 위해 user2.js 파일을 만들고 코드를 작성한다.
1
2
3
4
5
6
7
|
// Reason : exports는 속성으로, exports에 속성을 추가하면 모듈에서 접근하지만 exports에 객체를 지정하면 자바스크립트에서 새로운 변수로 처리한다.
exports = {
getUser : function(){
return {id : 'test01', name : '레드벨벳'};
},
group : {id : 'group01', name : '아이돌'}
}
|
cs |
이렇게 코드를 입력하면 getUser() 함수와 group 객체를 속성으로 가진 객체를 만들어 exports에 할당하게 된다.
따라서 exports 속성으로 getUser() 함수와 group 객체를 추가한 것과 같은 효과를 낸다.
일반적인 자바스크립트 코드에서는 user1.js 파일의 코드와 user2.js 파일의 코드가 같은 것처럼 보인다.
정상적으로 돌아가는지 확인하기 위해서 module_test2.js 를 만들고 코드를 입력한다.
1
2
3
4
5
6
7
8
9
10
11
12
|
// Reason : user2.js 파일에서 exports 에 객체를 할당하였으므로, require() 를 호출할 때 자바스크립트에서 새로운 변수로 처리함
// 결국 아무 속성도 없는 {} 객체가 반환됨.
var user = require('./user2');
console.dir(user);
function showUser(){
return user.getUser().name + ', ' + user.group.name;
}
console.log(showUser());
|
cs |
module_test1.js 파일에 입력한 코드와 같지만 require() 메소드로 불러들이는 모듈 파일의 이름을 ./user2 로 하였다.
그리고 user 변수에 할당한 객체의 속성 값을 확인하기 위해 console.dir() 메소드를 호출하였는데, 오류가 발생하면서 실행되지 않는다.
잘 보면 user 변수에는 객체가 할당되었지만 어떤 속성도 들어 있지 않다.
이 때문에 user 변수의 getUser() 메소드를 호출할 때 오류가 발생한 것이다. 왜 모듈을 불러와도 모듈 파일 안에서 exports에 할당한 객체가 보이지 않는 것일까?
노드는 모듈을 처리할 때, exports 를 속성으로 인식한다. 이 속성에 함수나 객체를 속성으로 추가하면 모듈을 불러들인 쪽에서 exports에 추가된 속성들을 참조할 수 있다.
그러나 exports에 객체를 할당하면 모듈 파일에서 선언한 exports 모듈 시스템에 처리할 수 있는 전역 변수가 아닌 단순 변수로 인식된다. 이 때문에 모듈을 불러들인 쪽에서 exports 를 참조할 수 없게 되고 결과적으로 모듈 파일을 불러들일 때 그 결과 객체에는 아무것도 들어있지 않게된다.
결국 user2.js 파일에서 exports 에 객체를 할당하면 전역변수 exports 와 무관한 모듈 파일 안의 변수가 되고 이 모듈을 불러들인 쪽에서는 비어 있는 exports 전역 변수만 참조하게 된다.
module.exports를 사용해서 객체를 그대로 할당하기
자바스크립트 코드를 만들 때 객체 안에 속성을 넣어 두는 경우가 많다.
따라서 모듈 파일에서 이 모듈을 불러들인 쪽으로 객체를 전달하는 것이 훨씬 편할 수 있다. 그렇다면 객체를 그대로 할당하는 방법은 없을까? exports 가 아니라 module.exports 를 사용하면 객체를 그대로 할당할 수 있다.
module.exports 를 사용해 보기 위해 user3.js 파일을 만들고 코드를 입력해보자.
1
2
3
4
5
6
7
8
9
|
// module.exports 에는 객체를 그대로 할당할 수 있다.
var user = {
getUser : function(){
return {id : 'test01', name : '레드벨벳'};
},
group : {id : 'group01', name : '아이돌'}
}
module.exports = user;
|
cs |
getUser() 메소드와 group 객체를 속성으로 갖는 객체를 새로 만들고 user 변수에 할당한다.
이 user변수는 다시 module.exports에 그대로 할당했다. 이제 user3.js 모듈을 사용하는 module_test3.js 를 만든다.
1
2
3
4
5
6
7
8
|
// require() 메소드는 객체를 반환함.
var user = require('./user3');
function showUser(){
return user.getUser().name + ', ' + user.group.name;
}
console.log('사용자 정보 : %s', showUser());
|
cs |
module_test3.js 파일의 코드는 module_test1.js 파일과 같으며, require() 메소드에 전달되는 파일 이름만 ./user3 으로 변경했다.
이 파일을 실행했을 때와 똑같은 결과가 콘솔 창에 표시된다. 모듈을 만들 때, module.exports에 객체를 그대로 할당하는 방식으로 만들었다는 점과 이 모듈을 require() 메소드로 불러들이면 그 객체가 그대로 반환된다는 것을 잘 이해해두자.
exports에 객체를 그대로 할당하면 모듈 파일을 불러들인 쪽에서 그 객체를 참조할 수 없지만, module.exports에 객체를 그대로 할당하면 모듈 파일 안에서 할당한 객체를 참조할 수 있다.
이 때문에 아무런 오류가 발생하지 않는다.
module.exports에 함수만 할당하기
module.exports에는 자바스크립트 객체만 할당할 수 있을까? 함수도 객체이므로 함수만 할당할 수도 있다. user4.js 파일을 만들고 다음과 같이 입력한다.
1
2
3
4
|
// 인터페이스(함수 객체)를 그대로 할당할 수 있음
module.exports = function(){
return {id : 'test01', name : '레드벨벳'};
};
|
cs |
이 파일에서는 익명 함수를 만들어 module.exports에 할당한다. 익명 함수에 들어있는 코드는 앞에서 만든 getUser 함수의 코드와 같다. 그리고 나서 이 모듈 파일을 불러들여 사용하는 기능을 module_test4.js 파일에 입력한다.
1
2
3
4
5
6
7
8
|
// require() 메소드는 함수를 반환함.
var user = require('./user4');
function showUser(){
return user().name + ', ' + 'No Group';
}
console.log('사용자 정보 : %s', showUser());
|
cs |
require() 메소드를 호출하면 모듈 파일 안에서 module.exports 에 할당한 익명 함수가 반환된다.
따라서 이 익명 함수를 user 변수에 할당했다면 user() 와 같이 소괄호를 붙여서 함수를 실행할 수 있다.
showUser() 함수 안에서 user 변수에 할당한 함수를 실행하면 id와 name 속성을 가진 객체가 반환되므로 그 객체의 name 속성을 참조할 수 있다.
module_test4.js 파일을 실행하면 다음과 같은 결과가 나타난다.
함수를 할당하면 모듈을 불러들인 쪽에서 그 함수를 그대로 참조할 수 있다.
따라서 반환된 함수에 소괄호만 붙여주면 함수를 그대로 실행할 수 있다. user 변수에 할당된 함수를 실행하면 사용자 정보가 들어있는 객체가 반환되므로 그 객체의 name 속성을 사용할 수 있다.
exports와 module.exports를 함께 사용하기
exports 와 module.exports 를 함께 사용하면 어떨까? 이 두 가지를 함께 사용하면 module.exports 가 우선으로 적용된다.
즉 모듈을 불러오는 쪽에서 module.exports에 할당된 객체나 속성을 참조할 수 있으며 exports 전역 변수는 무시된다.
module.exports 를 사용하는 것을 권장한다.
exports 를 사용하면 모듈을 불러들인 쪽에서 객체를 전달할 수도 없을 뿐더러 module.exports에 의해 무시되는 상황이 발생할 수 있다는 점에 주의하자. 따라서 실무에서는 module.exports 사용을 권장한다.
이 내용을 확인하기 위해서 user5.js 를 만들고 코드를 작성한다.
1
2
3
4
5
6
7
8
9
|
// module.exports 가 사용되면 exports는 무시됨.
module.exports = {
getUser : function(){
return {id:'test01', name:'레드벨벳'};
},
group : {id:'group01', name:'아이돌'}
}
exports.group = {id:'group02', name:'친구'};
|
cs |
module.exports에 객체를 그대로 할당했는데 그 객체에는 group 속성이 들어 있다. exports에도 group 속성을 추가하고 그 이름을 '친구'라는 정보를 넣었다.
이제 이 모듈 파일을 사용하는 module_test5.js 파일을 다음과 같이 만든다.
1
2
3
4
5
6
7
8
9
|
// require() 메소드는 export 가 아닌 module.exports로 설정된 속성을 반환함.
var user = require('./user5');
function showUser(){
return user.getUser().name + ', ' + user.group.name;
}
console.log('사용자 정보 : %s',showUser());
|
cs |
이 파일을 실행하면 그룹에 name 속성에 '아이돌' 이 나오고 '친구'는 나오지 않는다.
exports.group으로 할당한 '친구'는 적용되지 않았음을 확인할 수 있다.
이제 require() 메소드를 호출했을 때 모듈을 어떻게 불러오고 불러온 모듈을 어떻게 사용할 수 있는지 알아보았다.
그렇다면 require() 메소드를 호출했을 때 모듈 파일에서 설정한 객체나 함수를 그대로 반환받을 수 있다는 것도 이해할 수 있다.
require() 메소드의 동작 방식 이해하기
require() 메소드는 다른 모듈 파일에서 만든 객체를 참조할 수 있다. 이 require()메소드를 더 쉽게 이해하려면 가상의 함수를 만들어 보는 것도 좋은 방법이다. module_test6.js 파일을 만들고 다음과 같이 코드를 입력한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
// 가상으로 require() 함수를 정의해보면, require() 함수가 내부적으로 처리되는 방식을 이해할 수 있음
var require = function(path){
var exports = {
getUser : function(){
return {id:'test01', name:'레드벨벳'}
},
group : {id:'group01', name:'친구'}
}
return exports;
}
var user = require('...');
function showUser(){
return user.getUser().name + ', ' + user.group.name;
}
console.log('사용자 정보 : %s', showUser());
|
cs |
여기에서는 모듈을 불러올 때 사용한 require() 함수가 아닌, 우리가 직접 require() 함수를 새롭게 만들었다.
이 require() 함수는 한 개의 파라미터를 입력받으며, 이 파라미터를 모듈 파일의 이름처럼 전달한다.
require() 함수 안에서는 exports 변수를 만들어 객체를 할당했는데, 함수의 마지막 부분에서 exports 변수를 반환하도록 만들면 require() 메소드를 호출했을 때 이 객체를 반환받게 된다.
이제 아랫부분에서 require() 메소드를 호출한 후, 반환받은 객체의 메소드를 호출하거나 속성을 참조하도록 만든다. 이 부분은 모듈 파일을 불러올 때, 사용한 코드와 똑같에 구성한다.
따라서 module_test6.js 파일을 실행하면, 모듈 파일을 불러와 사용했을 때와 똑같은 결과를 얻을 수 있다.
이렇게 함수를 직접 만들어서 실행하면, 모듈 파일을 불러올 때 사용한 require() 함수가 어떻게 동작하는지 이해할 수 있다. 그리고 어떤 함수나 객체가 있을 때 이것을 별도의 모듈 파일로 분리시키는 방법에 아주 자연스러운 자바스크립트 코드 사용 패턴 중 하나라나는 것을 알게 될 것이다.
모듈을 분리할 때 사용하는 전형적인 코드 패턴
모듈을 분리할 때 사용하는 전형적인 코드 패턴으로는 세가지가 있다.
① "모듈 파일 안에서 함수를 할당하는 것"
② "모듈 파일 안에서 인스턴스 객체를 할당하는 것"
③ "모듈 파일 안에서 프로토 타입 객체를 할당하는 것" 이 있다.
코드 패턴 | 설명 |
함수를 할당하는 경우 | 모듈 안에서 함수를 만들어 할당하고, 소괄호를 붙여 모듈을 실행한다. |
인스턴스 객체를 할당하는 경우 | 모듈 안에서 인스턴스 객체를 만들어 할당하고, 해당 객체의 메소드를 호출하거나 속성을 사용할 수 있다. |
프로토 타입 객체를 할당하는 경우 | 모듈 안에서 프로토 타입 객체를 할당하고, new 연산자로 인스턴스 객체를 만들어 사용할 수 있다. |
이렇게 구분된 세 가지를 또, exports 전역 변수에 속성을 추가하는 경우와 module.exports에 할당하는 경우로 나눌 수 있다. (다만, 앞에서 본 것처럼 module.exports 사용을 권장한다.)
함수를 할당하는 코드 패턴
#user7.js
1
2
3
4
|
// 사용 패턴 : exports에 속성으로 추가된 함수 객체를 그대로 참조한 후 호출함
exports.printUser = function(){
console.log('user 이름은 쥬니입니다.');
};
|
cs |
- exports 전역변수에 printUser 를 추가했다.
#module_test7.js
1
2
3
4
|
// 사용 패턴 : exports에 속성으로 추가된 함수 객체를 그대로 참조한 후 호출함
var printUser = require('./user7').printUser;
printUser();
|
cs |
- require() 메소드로 불러오고, exports 의 printUser 속성이 함수이므로 속성을 바로 참조하기 위해,
"require('./user7').printUser;" 를 작성한다.
- printUser는 함수이기 때문에, 소괄호를 붙여준다.
인스턴스 객체를 할당하는 코드 패턴
파일 안에 인스턴스 객체를 만들어 할당한다.
#user8.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
// 사용 패턴 : module.exports에 인스턴스 객체를 만들어 할당함
// 생성자 함수
function User(id,name){
this.id = id;
this.name = name;
}
User.prototype.getUser = function(){
return {id:this.id, name:this.name};
}
User.prototype.group = {id:'group1', name:'친구'};
User.prototype.printUser = function(){
console.log('user 이름 : %s, group 이름 : %s', this.name, this.group.name)
};
module.exports = new User('test01', '레드벨벳');
|
cs |
- 함수를 생성자로 지정하여 객체를 정의하고, 그 객체를 사용해 인스턴스 객체를 만들 수 있다.
- User 라는 함수를 마늘고, id/name을 함수의 파라미터로 전달한다.
- this 를 사용해서 객체의 속성으로 추가한다.
- User.prototype 객체에 속성을 사용하여 속성을 추가한다.
#module_test8.js
1
2
3
4
5
|
// 사용 패턴 : module.exports에 인스턴스 객체를 만들어 할당함
var user = require('./user8');
user.printUser();
|
cs |
- require() 메소드를 사용하여 user8.js 파일에 정의한 모듈을 불러온다.
- User 인스턴스 객체에 printUser() 메소드가 추가되어 있기 때문에 user.printUser() 같은 형태로 메소드를 호출할 수 있다.
만약, 모듈을 만들 때 exports 를 사용해서 추가했다면, 이 객체를 어떻게 사용할까?
모듈을 불러들이는 쪽에서 require() 메소드를 호출한 후 반환되는 객체 속성으로 인스턴스 객체를 참조할 수 있다.
#user9.js
1
2
3
4
5
|
// 사용 패턴 : module.exports에 인스턴스 객체를 만들어 할당함
...
exports.user = new User('test01', '소녀시대');
|
cs |
- 위의 코드는 user8.js와 동일하지만, 마지막 부분에 module.exports에 인스턴스 객체를 할당했다면, exports.user 속성으로 인스턴스 객체를 추가한다.
#module_test9.js
1
2
3
4
|
// 사용 패턴 : exports의 속성 이름을 추가하되 인스턴스 객체를 만들어 할당함
var user = require('./user9').user;
user.printUser();
|
cs |
- require() 메소드로 모듈을 불러오고, 곧바로 반환된 객체의 user 속성을 참조한다.
- user 속성은 User에서 만든 인스턴스 객체를 의미하므로, user.printUser 같은 코드를 사용하면 User 안에 정의된 함수를 호출할 수 있다.
프로토타입 객체를 할당하는 코드 패턴
세 번째 패턴은 User 객체를 새로 정의한 후, module.exports에 직접 할당한다.
다시 말해, 앞에서 만든 User 객체로 인스턴스 객체를 만든 후 module.exports에 할당하는 것이 아니라, User 객체 자체를 module.export에 할당한다.
이렇게 하면 User 객체를 정의하는 부분만 별도의 모듈로 분리할 수 있으니, 다른 파일에서 필요할 때마다 직접 인스턴스 객체를 만들어 사용할 수 있다는 장점이 있다.
#user10.js
1
2
3
4
5
|
// 사용 패턴 : module.exports에 인스턴스 객체를 만들어 할당함
...
module.exports = User;
|
cs |
- 윗부분은 user9.js 와 같고 마지막 부분만 module.exports 에 User 객체를 직접 할당한다.
#module_test10.js
1
2
3
4
5
6
|
// 사용 패턴 : module.exports에 프로토타입 객체를 정의한 후 할당함.
var User = require('./user10');
var user = new User('test01', '소녀시대');
user.printUser();
|
cs |
- require() 메소드를 호출하여 모듈을 불러들인다. => User 객체 반환
- 프로토 타입 객체초 User 객체를 참조했으므로, new 연산자를 통해서 인스턴스 객체를 만든다.
- 그 안에 정의된 함수를 호출할 수 있다.
이러한 방법에서도 module.exports 말고, exports 로 객체에 속성을 할당하는 방식을 사용할 수 있다.
#user11.js
1
2
3
4
5
|
// 사용 패턴 : module.exports에 인스턴스 객체를 만들어 할당함
...
exports.User = User;
|
cs |
#module_test11.js
1
2
3
4
5
|
// 사용 패턴 : exports의 속성 이름을 주면서 추가하되 프로토 타입 객체를 정의한 후 할당함.
var User = require('./user11').User;
var user = new User('test01', '소녀시대');
user.printUser();
|
cs |
- require() 메소드로 모듈을 불러왔을 때, 반환되는 객체는 exports이므로 User 객체를 참조한 후 new 연산자로 인스턴스 객체를 만든다.
코드패턴이 다양해보일 수 있지만, 어떤 경우이든 별도의 모듈 파일에서 module.exprots에 객체를 할당하면 된다고 생각하면 쉽다.
그리고 module.exports에 할당된 객체나 exports에 속성으로 추가한 객체는 모듈을 불러왔을 때 그대로 참조할 수 있다는 것만 알아두면 된다.
'Theorem (정리) > node.js' 카테고리의 다른 글
(node.js) [Part.7] 익스프레스 프로젝트를 모듈화하기 - 설정 파일 만들기 (0) | 2021.01.25 |
---|---|
(node.js) [Part.7] 익스프레스 프로젝트를 모듈화하기 - 사용자 정보 관련 기능을 모듈화하기 (0) | 2021.01.23 |
(node.js) [Part.6] 데이터 베이스 사용하기 - MySQL 데이터베이스 사용하기 (0) | 2020.12.27 |
(node.js) [Part.6] 데이터 베이스 사용하기 - 비밀번호 암호화하여 저장하기 (0) | 2020.12.23 |
(node.js) [Part.6] 데이터 베이스 사용하기 - 인덱스와 메소드 사용하기 (0) | 2020.12.20 |