[Day 30] Hackathon Comment + Node.js + HTTP + Iterable
Hackathon Comment
- 프로그래머들은 항상 복잡성(Complexity)과 싸워야한다.
- 코드를 잘 정리해서 함수, 모듈, 파일 등으로 나눈다면 복잡성이 낮아지게 된다.
- 큰 프로그램을 작성하고 유지보수를 편하게 하기 위해서 복잡성을 낮춰야 한다.
- 협업을 잘 하기 위해서도 복잡성을 낮춰야 한다.
- 폭포수(Waterfall) 개발 방법론
- 애자일(Agile) 개발 방법론
- 일정을 잘 관리해야 한다.
해야 하는 일
과하고 싶은 일
을 잘 구분해서!- 어떤 일을 하는 데 어느 정도의 시간이 걸리겠다는 것을 측정할 때, 굉장히 보수적으로 측정해서 내가 생각한 것보다 2~3배 더 많이 걸릴 것으로 예상해야 한다. (실제로 온갖 버그와 문제점들 때문에 생각한 것보다 오래 걸린다.)
- 작업하는 순서는
꼭 해야 하는 일
부터!!- MVP(Minimum Viable Product) 최소 기능 제품을 먼저 만들고 난 뒤 하고 싶은 일을 해야 한다.
- MVP 조차 기한내에 맞추지 못한다면 Plan B를 세워서 어떻게든 기능을 만들어내야 한다.
Node.js + HTTP
Node.js
// Node.js module 사용하기
$ const os = require('os') // 급할땐 `os = ...`
undefined
// node.js 프로그램이 어떤 운영체제 위에서 실행되고 있는지
$ os.platform()
'linux'
// 가용한 메모리
$ os.freemem()
658300928
-
Node.js로 파일 실행시키기
$ node (파일 경로)
-
Node.js
- Chrome에서 사용되는
V8 JavaScript engine
을 사용한다. - 통신도 이벤트 핸들러를 붙이는 방식(
event-driven
)으로 이루어진다. - 아주 빠른 속도로 많은 요청을 처리할 수 있는
non-blocking I/O moedl
을 사용한다. - Node.js의 package ecosystem인
npm
은 세계에서 가장 거대한 오픈소스 라이브러리 생태계를 갖고 있다.
- Chrome에서 사용되는
-
Node.js Module
// name.js // `module.exports`에 저장한 값은 다른 모듈에서 불러올 수 있음 module.exports = { familyName: '김', givenName: '승하', fullName: function() { return this.familyName + this.givenName } }
// calc.js // `exports`로도 참조 가능 exports.add = (x, y) => x + y exports.sub = (x, y) => x - y
// Node REPL에서 모듈 불러오기 // Node.js 내장 모듈과는 다르게 경로를 지정해야 함 $ const name = require('./name') undefined $ name { familyName: '김', givenName: '승하', fullName: [Function: fullName] } > name.familyName '김' > name.fullName() '김승하' > require('./calc').add(1, 2) 3
npm
- npm
- Node.js 패키지 관리 도구 + 클라우드 패키지 저장소
- 의존 패키지 관리
- 스크립트 실행
- 패키지 설정
- NPM에 패키지 배포
- Node.js 종합 작업 도구
-
package.json : 패키지 정보를 담고 있는 파일
-
dependencies :
npm install --save
명령으로 설치한 패키지가 기록된다.-
어떤 라이브러리를 설치했는지 자동으로 기록된다.
- package-lock.json에도 라이브러리 설치 기록이 남아있기 때문에 node_modules 폴더가 날라가도
npm install
을 다시 하면 그대로 설치된다. - 협업을 위해 github에 올릴 때 용량을 줄이기 위해 node_modules 폴더는 올리지 않는다. (gitignore에 설정한다.)
- package.json / package-lock.json 만 git에 올리고 필요시 npm install 해서 사용하도록 한다.
-
-
scripts : 원래 목적은 패키지 생명주기마다 자동으로 실행되는 명령을 등록하기 위함이나, 개발자 편의를 위해 자주 사용되는 명령을 등록하는 용도로 더 많이 사용된다.
-
package.json의 “scripts” 속성에 key/value 형태로 등록해서 사용한다.
// package.json "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "node index.js" }, // 등록하고 나면 npm start 를 입력했을 경우 node index.js가 실행된다.
-
-
-
과거 npm은 Node.js의 라이브러리들만 다운받아서 사용하는 클라우드 저장소였지만, 최근에는 FrontEnd 라이브러리들(jQuery, css reset 등등…)도 npm을 통해 다운받아서 사용할 수 있다.
- 과거에는 FE 라이브러리를 다운받는 클라우드 저장소로
Bower
를 많이 사용했었지만 2015년을 기점으로 거의 사장되었다.
- 과거에는 FE 라이브러리를 다운받는 클라우드 저장소로
HTTP(HyperText Transfer Protocol)
-
웹 브라우저와 웹 서버 간의 통신을 위해 개발된 통신규약
-
최근에는 REST API의 부상과 함께 다른 용도로도 널리 사용된다.
- 모바일 앱 - 서버 간 통신
- 서버 - 서버 간 통신
-
80번 포트를 기본으로 사용
- 컴퓨터에 통신을 위한 수많은 콘센트가 있고, 거기에 번호가 붙어 있을 때 그 번호를 포트(Port)라고 한다.
-
클라이언트의 요청(request)과 서버의 응답(response)으로 이루어짐
- 요청 한번 보내고, 응답 한번 받으면 연결이 끊어진다. (하나의 사이클)
-
HTTPS (HTTP over SSL(secure socket layer))
- HTTP 통신을 암호화해 주고받는 내용을 중간에서 가로챌 수 없도록 함
- 443번 포트를 기본으로 사용
-
HTTP/2
- 구글의 SPDY 프로토콜을 기반으로 2015년에 확정된 새로운 HTTP 표준
- 속도 개선에 중점을 두고 개발됨
- 반드시 HTTPS를 사용해야 함
- 현재 전체 웹사이트 중 26% 이상이 사용 중
-
Request & Response
- 웹 브라우저(또는 다른 클라이언트)는 웹 서버에 요청(request)을 보낸다.
- 그에 따라 서버는 클라이언트에 응답(response)을 보냄
- 웹 브라우저의 경우, HTML 문서 형태의 응답이 오면 해당 문서를 분석한 후, 문서에 포함된 모든 자원에 대한 요청을 각각 추가로 보낸다. (이미지, 동영상, 오디오, CSS, JS, 폰트, …)
-
Request Methods (요청 메소드)
- HTTP 명세에는 8종류가 등록되어 있고, 각각의 역할과 충족해야 하는 성질이 명시되어 있다.
- 웹 브라우저는 특정 상황에서 특정 메소드로 요청을 보내도록 만들어져 있다.
- Ajax와 같이 요청을 보내는 코드를 직접 짤 때는 요청 메소드를 선택할 수 있다.
- 자료의 본문을 요청하는
GET 메소드
와 새로운 자료를 등록하는POST
메소드가 가장 많이 쓰인다. - Method Definitions
-
URL
-
Percent Encoding
-
URL은 ASCII 문자 밖에 사용하지 못하기 때문에, non-ASCII 문자를 위한 표현방법이 필요하다.
-
Percent Ecoding은 non-ASCII 문자를 위한 웹 표준 인코딩 방법으로, Javascript에 관련 기능이 포함되어 있다.
$ encodeURIComponent("한글") "%ED%95%9C%EA%B8%80" $ decodeURIComponent("%ED%95%9C%EA%B8%80") "한글"
-
-
-
Response Status
- HTTP Status Codes
- Status Category
2xx
: 성공200 OK
: 성공201 Created
: 자료가 성공적으로 생성됨
3xx
: 추가 작업이 필요함301 Moved Permanently (Redirection)
: 자료가 완전히 다른 곳으로 이동했음302 Found (Redirection)
: 자료가 일시적으로 다른 곳에 있음304 Not Modified (Cache)
: 클라이언트가 이미 가지고 있던 자료가 수정되지 않았음 (그대로 사용하면 됨)
4xx
: 실패 - 클라이언트 책임400 Bad Request
: 요청의 형태가 잘못되어 응답할 수 없음403 Forbidden
: 요청한 자료에 접근할 권한이 없음404 Not Found
: 요청한 자료가 없음
5xx
: 실패 - 서버 책임500 Internal Server Error
: 요청을 처리하던 중에 예상치 못한 오류가 발생함503 Service Unavailable
: 서버가 일시적으로 응답을 할 수 없음
-
Header
- 요청과 응답에 대한 추가 정보를 표현하는 데 사용된다.
- 인증, 캐싱, 쿠키, 보안, 프록시 등 웹 표준에 정의된 많은 기능을 제어하는데 사용된다.
- Authorization : 요청의 인증 정보
- User-Agent : 요청 중인 클라이언트의 정보
- Location : 301, 302 응답에서 자료의 위치
- Accept : 요청이 어떤 형태의 자료를 원하는지 나타냄
- Content-Type :요청 혹은 응답이 어떤 형태의 자료인지 나타냄
Iterable
- 반복 가능한 객체(iterable object)는 ES2015에서 도입되었다.
- 이터러블 객체가 다른 객체와 다른 점은 객체의
Symbol.iterator
속성에 특별한 형태의 함수가 들어 있다는 것이다. - 이터러블이 가능할 경우 해당 객체는 iterable protocol을 만족한다고 표현한다.
- iterable 객체를 만들어내는 생성자
String
Array
TypedArray
Map
Set
Iterable의 사용
-
어떤 객체가 Iterable이라면, 그 객체에 대해 이러한 기능들을 사용할 수 있다.
for...of
루프- spread 연산자(
...
) - 분해대입(destructuring assignment)
- 기타 iterable을 인수로 받는 함수
// `for...of` for (let c of 'hello') { console.log(c); } // spread 연산자 const characters = [...'hello']; // 분해대입 const [c1, c2] = 'hello'; // `Array.from`은 iterable 혹은 array-like 객체를 인수로 받습니다. Array.from('hello');
Generator 함수
-
iterable protocol을 구현하기만 하면 어떤 객체든 iterable이 될 수 있다.
- 너무 어려운 방법이다 ㅠㅠ
- 대신, Generator 함수(ES2015)를 사용하면 쉽게 iterable 객체를 만들 수 있다.
-
Generator 함수는 iterable 객체를 return하는 특별한 형태의 함수이다.
-
generator 함수 정의
// generator 함수 선언하기 function* gen1() { // ... } // 표현식으로 사용하기 const gen2 = function* () { // ... } // 메소드 문법으로 사용하기 const obj = { * gen3() { // ... } }
-
Generator 함수를 호출하면 객체가 생성되는데, 이 객체는 iterable protocol을 만족한다. 즉,
Symbol.iterator
속성을 갖는다.function* gen1() { // ... } // `gen1`를 호출하면 iterable이 반환됩니다. const iterable = gen1(); iterable[Symbol.iterator]; // [Function]
-
Generator 함수 안에서는
yield
라는 키워드를 사용할 수 있다.yield
키워드는 return과 유사한 역할을 하며, iterable 기능을 사용할 때yield
키워드 뒤에 있는 값들을 순서대로 넘겨준다.function* numberGen() { yield 1; yield 2; yield 3; } // 1, 2, 3이 순서대로 출력됩니다. for (let n of numberGen()) { console.log(n); }
-
yield*
표현식을 사용하면, 다른 Generator 함수에서 넘겨준 값을 대신 넘겨줄 수도 있다.function* numberGen() { yield 1; yield 2; yield 3; } function* numberGen2() { yield* numberGen(); yield* numberGen(); } // 1, 2, 3, 1, 2, 3이 순서대로 출력됩니다. for (let n of numberGen2()) { console.log(n); }
-
Generator 함수의 활용 예시
- Generator 함수를 사용하면 좋은 점
- 무한 배열을 생성할 수 있다.
- 루프(loop)를 값으로 사용할 수 있다. (값의 변경, 조합 등 추가적인 작업이 가능해진다.)
- 값으로 만들어진 것들은 조합성이 좋기 때문에 나중에 변경을 쉽게 할 수 있다.
- 루프를 기능으로 분리해낼 수 있다.
// 등차수열 생성하기 function* range(start = 0, end = Infinity, step = 1) { for (let i = start; i < end; i += step) { yield i; } } // 피보나치 수열 생성하기 function* fibonacci(count = Infinity) { let x = 1; let y = 1; for (let i = 0; i < count; i++) { yield x; [x, y] = [y, x + y]; } } // 하나의 항목을 계속 넘겨주기 function* repeat(item, count = Infinity) { for (let i = 0; i < count; i++) { yield item; } } // 여러 요소를 반복해서 넘겨주기 function* repeatMany(array) { while (true) { for (let item of array) { yield item; } } }
- Generator 함수를 사용하면 좋은 점
-
Generator 함수를 사용할 때 주의할 점!!
-
Generator 함수로부터 생성된 iterable 객체는 한 번만 사용될 수 있다.
- 모든 iterable 객체에 해당되는 것은 아니다. 문자열이나 배열도 iterable 객체이지만 횟수에 제한 없이 사용할 수 있다.
// Generator 함수로부터 생성된 iterable은 한 번만 사용될 수 있습니다. function* gen() { yield 1; yield 2; yield 3; } const iter = gen(); for (let n of iter) { // 잘 출력됩니다. console.log(n); } for (let n of iter) { // `iter`는 한 번 사용되었으므로, 이 코드는 실행되지 않습니다. console.log(n); }
-
Generator 함수 내부에서 정의된 일반 함수에서는
yield
키워드를 사용할 수 없다.// Generator 함수 내부에서 정의된 일반 함수에서는 `yield` 키워드를 사용할 수 없습니다. function* gen2() { // 아예 문법 오류가 납니다. (Unexpected token) function fakeGen() { yield 1; yield 2; yield 3; } fakeGen(); }
-
-
Generator란 무엇인가?
-
Generator는 값을 여러번 뱉어낼 수 있는 함수이다. (조합성이 좋아진다.)
-
일시정지도 할 수 있다.
function* myGen() { console.log('hello') yield 1 console.log('hello 2') yield 2 console.log('bye') } const iterable = myGen() iterable.next() iterable.next() iterable.next() // next() 메소드를 실행하면 해당 generator를 실행하는데, yield를 만나면 일시정지 한다. // yield 를 만나면 일시정지 하면서 { value: (...), done: (false/true) } 를 return 한다. // iterable 객체의 value는 yield가 return하는 값이고, done은 함수의 종료 여부를 return 한다. // 함수의 맨 마지막 까지 진행됐다면 done: true를 return 한다.
-
Generator 사용 예제
- 제너레이터와 실행기를 이용한 Delay
// 제너레이터 정의 function* genCoroutine() { console.log('hello') yield { type: 'delay', delay: 1000 } console.log('bye') yield { type: 'delay', delay: 2000 } console.log('last') } // 제너레이터 실행기 정의 function runCoroutine(co) { const value = co.next().value if (value.type === 'delay') { setTimeout(() => { runCoroutine(co) }, value.delay) } } // 제너레이터 실행 runCoroutine(genCoroutine())
-
댓글남기기