[Kakao Cloud School] 3번째 회고록

lango·2022년 11월 21일
0
post-thumbnail

Intro


혼자서 꾸준히 공부하는 것은 어렵다.

3주차 교육까지 HTML5와 JavaScript, Node.js를 공부하면서 재미있기도 하지만, 모르는 것도 많고, 실무에선 어떻게 적용하는 것이 더 좋을까하는 고민도 많아졌다.

코어 타임과 별도로 시간을 투자하여 혼자서 자습한다는 것이 쉽지 않음을 느꼈다. 그래서 같은 교육생들과 주마다 배운 내용을 가지고 소규모 과제를 수행하는 스터디 모임을 꾸리게 되었다.

혼자서는 어렵고 귀찮았던 공부시간들이 동료들에게 어떻게 쉽게 설명해줄 수 없을까 고민하던 시간들로 바뀌고 그 고민들은 남에게 설명하거나 알려주기 위한 학습을 하도록 도와주었다.

혼자서 거창한 것을 하려면 어렵고 힘들지만, 동료들과 함께 조금씩이라도 꾸준히 성장하기 위해서 시너지를 줄 수 있는 협업 공동체 환경을 잘 가꾸어 나가야 겠다고 생각이 들었다.




Day - 9

3주차 교육이 시작되었다. 정확하게 알지 못했던 SOP와 CORS에 대해서 알아볼 수 있었다.

SOP와 CORS

브라우저의 보안과 관련된 SOP와 CORS에 대해서 간단하게 알아보려 한다.

SOP(Same Origin Policy, 동일 출처 정책)란?
특정 출처(origin)에서 불러온 문서 및 스크립트가 또 다른 출처에서 가져온 리소스와 상호 작용하는 것을 제한하는 브라우저의 보안 방식이다. 말 그대로 동일한 출처에서 온 요청만 처리하는 것이다.

CORS(Cross-Origin Resource Sharing, 교차 출처 리소스 공유)란?
추가 HTTP 헤더를 사용하여 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제이다.

CORS 이슈

다른 도메인의 데이터를 가져와서 사용하고자 할 경우 CORS 정책을 위반하여 에러가 발생할 수 있다. CORS 이슈를 해결할 수 있는 방법은 무엇일까? 서버 소스에 접근하여 수정할수 있냐 없냐로 해결방식이 구분된다.

  • 서버에 접근 가능하다면
    서버 쪽 코드를 수정할 수 있다면 가장 간단하게 해결할 수 있다. 바로 서버에서 요청을 보내는 브라우저의 오리진을 허용하여 헤더에 추가해주면 된다. 그렇담 어떤 헤더를 추가해야 할까? 서버에서 모든 클라이언트에 요청에 대한 Access-Control-allow-origin 헤더를 추가하면 된다.

  • 서버에 접근이 불가능하다면
    외부에 있는 서버와 통신한다면 서버에 접근할 수 있는 권한이 없기에 별도로 오리진을 허용할 수가 없다.
    그렇기에 별도로 proxy 서버를 하나 두고 그 서버가 외부 서버와 소통하게 하는 방법이 있다. 즉, 중계 서버를 만들어 브라우저 대신 요청을 보내고 받아와 다시 브라우저에게 전달해주는 것이다. 바로 Webpack DevServer Proxy을 활용하여 요청과 응답을 대신하는 프록시 서버를 활용할 수 있다.



YAML VS Properties

properties 방식으로 작성한 파일과 YAML 방식으로 작성한 내용을 비교해보자.

Properties 방식으로 작성

spring.datasource.url=jdbc:h2:dev
spring.datasource.username=SA
spring.datasource.password=password

YAML 방식으로 작성

spring:
    datasource:
    	url: jdbc:h2:dev
        username: SA
        password: password

두가지 방식의 차이점은 바로 알아차릴 수 있는데, properties 방식의 경우는 동일한 key값이 많이 작성될 수 있지만, YAML방식은 이러한 동일 key값을 작성할 필요가 없다. 덕분에 가독성도 높아져 개발자가 읽기에도 쉽다.

가능하다면 YAML 방식으로 작성하는 습관을 들이자.



ImageSprite란?

이미지 파일을 사용해야 할 때 여러개의 이미지 파일을 서버에 업로드하여 사용하는 것을 떠올리는 데 여러 개 파일을 업로드할 필요없이 하나의 파일에서 여러개의 이미지를 관리할 수 있는 방법이 있다. 바로 image sprite이다.

image sprite란 여러개의 이미지를 적절한 크기로 편집하고 하나의 파일로 만들어 사용하는 개념이다.

위처럼 하나의 파일로 이루어진 이미지에서 상, 하, 좌, 우 화살표를 위치별로 잘라서 사용한다면 리소스를 아낄 수 있다.

이미지를 각각의 파일로 저장해서 읽어오는 것보다는 하나의 파일로 읽어들인 후 정해진 이미지의 위치별로 잘라 사용하는 것이 더욱 효율적이다.



Day - 10

10일차가 마무리되었다. XHTML, CSS, JS, HTML5에 대해서 배웠다. 출력된 화면에 디자인을 적용하는 CSS, 출력된 화면의 요소들을 동적으로 제어하는 JavaScript, 서버에서 데이터를 받아오는 기술인 JavaScript의 ajax, fetch API 등을 학습하며 웹 브라우저에 어떤 것을 출력하고 제어하기 위한 기술들의 이해도를 높일 수 있었다.


Geo Location(위치정보)

Geo Location은 디바이스의 물리적 위치 정보, 즉 사용자의 현재 위치를 가져올 때 사용하는 JavaScript API이다.

사용자의 위도 및 경도에 관한 정보는 자바스크립트를 이용해 웹 서버로 전송되는데 사용자의 위치를 지도에 표시하거나, 사용자 근처의 상점을 찾아주는 등의 위치기반 서비스를 개발할 수 있다.

하지만 이러한 정보는 사용자의 사생활을 침해할 가능성이 높으므로, 필수적으로 사용자 동의를 받고 위치정보를 수집하도록 하고 있다.

Geo Location을 활용한 간단한 예제를 작성해보자.

navigator.geolocation.getCurrentPosition((pos) => {
	console.log(pos.coords.latitude, pos.coords.longitude);
}, (err) => {
	console.log(err.code, err.message);
});

위치정보가 허용된 상태라면 위 코드를 통해 현재 위치의 위도와 경도값을 가져올 수 있다.


Kakao Map 활용

그렇다면 Geo Location API와 카카오에서 제공하는 지도 API를 활용하여 현재 위치를 지도위 마커로 찍어볼 수 있지 않을까?

카카오 지도 API를 연동하는 과정은 카카오 맵을 참고하면 쉽게 구현할 수 있다.

<div id="map" style="width:500px;height:400px;"></div>

먼저 지도영역을 만들어주고 실제 지도를 그리는 Javascript API를 불러온다. 이때 발급받은 key를 함께 작성하면 된다.

navigator.geolocation.getCurrentPosition((pos) => {
	let container = document.getElementById("map");
	let options = {
    	center: new kakao.maps.LatLng(pos.coords.latitude, pos.coords.longitude),
      	level: 3
    };
  	let map = new kakao.maps.Map(container, options);
  	let markerPosition = new kakao.maps.LatLng(pos.coords.latitude, pos.coords.longitude);
  	let marker = new kakao.maps.Marker({
    	position: markerPosition
    });
  	marker.setMap(map);
}, (err) => {
	console.log(err.code, err.message);
});

현재위치를 카카오 지도 위에 마커로 표시하는 동작을 하도록 코드를 작성하였다. 가이드대로만 작성하면 되니 쉽게 구현할 수 있었다.

하나의 위치뿐만 아니라 위치정보가 포함된 대량의 데이터들을 지도 위에 출력하거나 마커 인포윈도우, 마커 클러스터링 등의 기능들도 짬내서 구현해볼 수 있지 않을까? 생각이 들었다.

따릉이 대여소 위치 카카오맵에 출력하기

별도로 공공 데이터를 활용해 서울시 따릉이 대여소의 거치대수를 가져와서 카카오맵 위에 마커를 출력해보는 과제를 수행하였다. 관련 소스코드는 링크에 첨부하였다.



왜 브라우저에 데이터를 받아두는 걸까?

브라우저 내에 특정한 데이터를 저장하는 것에 대해서 잘 모르고 있었다. 왜 데이터들을 브라우저에 담아두는 걸까?

첫번째 이유는 불필요한 트래픽을 줄이기 위함이다. 예를 들어 메일의 경우 매번 서버에 접속하여 데이터를 받아온다면 불필요한 자원 낭비가 될 수 있다.

그렇기에 실제로 구현할 때는 파일의 존재여부를 확인하여 최초 접속시에만 데이터를 다운로드 받도록 해야한다. 그리고 최초 접속 이후부터는 최신 업데이트 시간을 확인 및 비교하여 최신 데이터를 다운로드 받아오는 방식으로 구현해야 한다.

두번째로는 오프라인 상태에서도 데이터를 사용하기 위함이다.
배달과 관련된 애플리케이션을 예로 들면 네트워크 연결이 끊어져도 이전의 가게들을 확인하고 전화 정도는 할 수 있어야 함을 알 수 있다.


브라우저에 데이터를 저장하는 방법

그렇다면 브라우저에 데이터를 어떤 방식으로 저장하는 걸까?
브라우저에 데이터를 저장하는 방식들에 대해서 간단하게 살펴보자.

  • Web Storage: 브라우저가 쿠키를 사용하는 것보다 훨씬 더 직관적인 방식으로 키/값 쌍을 저장할 수 있는 메커니즘을 제공 하는 방식으로 데이터가 Map 형태로 저장된다.

쿠키(Cookie)란?
쿠키는 웹사이트 접속시 접속자의 개인장치에 다운로드 되고 브라우저에 저장되는 작은 텍스트 파일이다. 쿠키는 유저들의 효율적이고 안전한 웹 사용을 보장하기 위하여 웹사이트에 널리 사용되고 있다. 웹사이트는 쿠키를 통해 접속자의 장치를 인식하고, 접속자의 설정과 과거 이용내역에 대한 일부 데이터를 저장한다.

  • 클라이언트에 최대 300개까지 쿠키를 저장할 수 있으며, 하나의 도메인당 20개의 값만 가질 수 있다. (하나의 쿠키값은 4KB까지 저장이 가능하다.)
  • Local Storage(영구저장소): 브라우저에 저장하여 영구적인 상태로 보존되는 저장소이다.

  • Session Storage(내부저장소): 접속중인 브라우저의 생명주기에 따라 접속 후 종료되는 시점에 소멸되는 저장소이다.

  • Web SQL: HTML5는 RDB(관계형 데이터베이스)가 추가로 제공된다. 보다 구조적이고 체계화된 관계형 데이터를 대랑으로 저장하기에 적합하다. (SQLite 3를 이용한다.)

  • indexed DB: 사용자의 브라우저에 데이터를 영구적으로 저장할 수 있는 방법이다. 애플리케이션이 온/오프라인 환경에서 모두 동작할 수 있도록 도와준다. NoSQL과 유사하게 자바스크립트 객체 형태로 저장된다.

기존에는 쿠키를 사용했는데, 쿠키를 사용하게 되면 문자열로만 저장할 수 있고 서버에게 매 번 전송된다. 그렇기에 전송여부를 클라이언트가 결정할 수 없다는 단점이 있다.

오늘은 Web Storage의 Session Storage와 Local Storage를 알아보려 한다.

Session Storage

페이지의 세션 기간 동안만, 즉 브라우저가 열려 있는 동안 저장 영역을 유지해주는 저장소이다. 세션 동안만 데이터를 저장하기 때문에 브라우저를 종료한다면 데이터가 삭제된다. 저장 한도는 최대 5MB 쿠키보다 크다.

Local Storage

로컬 스토리지는 브라우저에 저장되면 브라우저의 종료여부에 관계없이 데이터를 유지하게 된다.

로컬 스토리지는 보안이 중요하지 않은 많은 양의 데이터를 저장하는데 용이하다. 주로 장바구니나 아이디 저장 등의 방식들에 활용될 수 있다.

동일한 패턴으로 이루어진 데이터가 많다면 Local Storage보단 Web SQL이나 Indexed DB를 사용하는게 더 좋다.

Session Storage VS Local Storage

Session Storage와 Local Storage 모두 데이터를 브라우저에 저장한다는 공통점을 가지고 있으며, 자바스크립트 API가 완전히 동일한 형태이기에 사용하기에도 매우 쉽다.

두 가지의 차이점은 결국 데이터의 생명주기 시점에 따라 구분된다고 생각한다. session storage는 브라우저의 세션이 끝날 때 저장된 데이터가 지워지며 local storage는 브라우저의 세션이 끝나더라도 데이터를 유지해준다.

즉, 하나의 브라우저에서 같은 사이트를 여러 탭으로 띄워놓으면 여러개의 session storage에 각각 데이터를 보관하고, 각각의 탭이 종료되면 해당 session의 데이터만 소멸된다. 반면에 local storage는 여러 탭을 띄워놓아도 각 탭마다 데이터가 공유되며 탭뿐 아니라 브라우저가 종료되어도 다시 실행하면 해당 데이터들이 유지된다.

결국 하나의 브라우저에서만 데이터가 유지되기에 다른 기기나 브라우저 간 데이터를 공유해야 한다면 클라우드나 데이터베이스를 활용하는 것이 바람직할 것이다.



Web Worker와 비동기 함수의 차이는?

싱글스레드 기반으로 작동하는 자바스크립트는 싱글스레드의 단점을 보완하기 위해 코드들이 비동기로 실행된다. 그러나 비동기 처리 작업이 너무 많이 쌓이게 되면 모든 작업의 실행 속도가 느려질 수 있다. 이 문제를 해결하기 위해 나온 것이 바로 Web Worker이다.

Web Worker는 멀티 스레딩을 지원하게 되어 워커를 이용하면 워커에서 작성된 스크립트는 메인 스레드에서 분기되어 독립된 스레드로 실행되기 때문에 메모리 자원을 효율적으로 사용할 수 있다.

Thread와 유사한 개념으로 자바스크립트에서는 Thread 대신에 Worker라는 표현을 사용한다. Web Worker와 달리 async와 같은 비동기 처리함수는 별도의 스레드에서 실행되도록 보장되지 않는다. 즉, 결과를 받을 때까지 대기시간이 발생한다는 것이다.

정리하자면, HTML과 함께 존재하는 JavaScript 코드에서 오래 걸리는 작업을 수행한다면 작업이 끝날 때까지 클라이언트 입장에서는 아무 것도 할 수 없어 다른 작업을 수행할 수 없다. 그래서 사용자 입장에서 큰 불편함이 생긴다.

대표적인 내장 비동기 함수인 setTimeout을 예로 들어보겠다.

let job = () => {
        setTimeout(() => {
            const stt = Date.now();
            for (let i = 0; i < 100000000000; i++) { }
            const edt = Date.now();
            console.log((edt - stt) + " 밀리초");
        }, 0);
    }

위 코드는 100000000000이라는 큰 수만큼 반복하며 걸리는 시간을 구하는 로직이다. job 함수를 실행하게 되면 비동기 함수임에도 불구하고 화면이 멈추고 사용자는 아무것도 못하게 된다.

Web Worker로 위 문제를 해결해보자.

let start = Date.now();
// worker를 통해 누적 합 작업을 시키면 클라이언트는 다른 작업을 할 수 있다.
let worker;
// 워커가 생성되어 있다면 중지시킨다.
if (worker) worker.terminate();
// 워커 생성
worker = new Worker("/resources/worker2.js");
// 워커에게 메시지(작업) 전송
worker.postMessage(start);
// 워커에게서 받은 결과
worker.onmessage = (e) => {
    printArea.innerHTML = `걸린 시간은 ${e.data} 밀리초 입니다.`;
};
// worker.js
onmessage = (e) => {
    let res;
    setTimeout(() => {
        let start = e.data;
        for (let i = 0; i < 100000000000; i++) { }
        const edt = Date.now();
        res = (edt - start);
        // 작업 결과를 html에게 전송한다.
        postMessage(res);
    }, 0);
};

Worker.js 파일을 별도로 만들어 html 파일에서 worker에게 작업을 지시하면 worker 내부에서 100000000000만큼 반복하며 걸리는 시간을 구해 반환하는 작업을 하도록 작성하였다.

Web Worker로 해당 로직을 실행하니 이전 비동기 함수를 실행했을 때와는 달리 결과를 바로 받진 못하더라도 화면에서 버튼을 누를 수 있는 등 다른 작업을 할 수가 있었다.

자바스크립트로 무거운 동작을 해야하는 작업은 가능하다면 Web Worker를 통해 작업을 지시하는 것이 사용자의 불편함을 줄일 수 있을 것이라고 생각이 들었다.



Day - 11

JavaScript 기초 교육을 마쳤다. 본격적으로 Node.js에 대해서 배우기 시작했는데, 기대하던 서버 프로그래밍 공부를 하게 되어 들뜬 날이었다.


Node.js는 왜 등장하게 되었나?

Node.js를 익히 들어보았지만, 이번에 배우게 되면서 여러가지 의문점들이 생기기 시작했다. 등장 배경부터 천천히 살펴보려 한다.

Node.js(이하 node)는 어떤 필요에 의해서 나오게 되었을까?
먼저 node는 Chrome V8 JavaScript 엔진을 사용해서 애플리케이션을 개발할 수 있는 JavaScript Runtime이라고 한다.

Runtime(런타임)이란?
특정 언어로 만든 프로그램들을 실행할 수 있게 해주는 환경을 뜻한다.

  • JavaScript Runtime이라하면 결국 JavaScript를 실행하도록 도와주는 환경이다.

Chrome V8 JavaScript 엔진이란?
2008년에 구글에서 발표한 자바스크립트 엔진으로 여타 자바스크립트 엔진 중 가장 빠른 속도를 보여준다.

Chrome V8 JavaScript 엔진은 자바스크립트를 웹 브라우저 환경에서 벗어나면 발생했던 속도 이슈를 해결할 수 있었다. 그래서 Ryan Dahl이라는 사람이 chrome V8 엔진을 기반으로 한 node를 개발하였다.

node는 비동기(I/O) 이벤트를 주도하는 자바스크립트 런타임으로 다양한 애플리케이션을 만들 수 있도록 설계되어 자바스크립트로 서버도 개발할 수 있는 환경이 주어진 것이다.

그렇게 node는 강력한 런타임 환경에서 빈번한 비동기(I/O) 이벤트 처리에 있어서의 우수한 성능, 서버 확장의 용이성, 그리고 프론트엔드 언어인 JavaScript로 백엔드 단까지 작성할 수 있다는 장점 때문에 출시 이후로 빠르게 점유율을 높여가고 있는 추세이다.

또한 node 기반의 수많은 라이브러리 등장과 함께 npm(Node Package Manager) 이라는 패키지 관리자도 등장하였고, npm의 성장은 node 기반 라이브러리들을 빠르게 불러올 수 있어 개발하는데 높은 생산성을 부여하게 되었다.



Day - 12


Call by Value와 Call By Reference

메소드에 값을 전달하는 것과 객체를 전달하는 것에는 큰 차이가 있다. Call by Value와 Call By Reference에 대해서 알아보자.

Call By Value(값에 의한 호출)란?
함수를 호출할 떄 전달되는 변수의 값을 복사한다. 복사된 인자는 지역변수로 사용되기에 함수 내부에서 인자 값이 바뀌어도 외부 값은 변하지 않는다. 원본 값이 변하지 않기 때문에 안전하지만 원본을 복사한 사본이 생성되기에 메모리 양이 늘어난다.

Call By Reference(참조에 의한 호출)란?
인자로 받은 값의 주소를 참조하여 처리한다. 함수 내에서 인자 값이 변경되면, 매개변수로 전달된 값도 함께 변경된다. 원본 값을 복사하여 사본을 생성하는 것이 아니기에 속도가 빠르지만 직접 원본값을 참조하기 때문에 원본값에 영향을 줄 수 있다.


먼저 Call By Value의 예시를 작성해보았다.

let num = 1;
const numIncrease = (number) => {
    number++;
    console.log(number);
}
numIncrease(num);
console.log(num);

// output
// 2
// 1

위 코드를 보면 num이라는 변수를 numIncrease 메서드의 인자로 넘겨주었다.
그런데, 메서드 내에서의 number은 2가 출력되었고, 메서드 실행 종료후 num은 다시 1이 출력되었다.

num과 number의 값은 같지만 num변수를 복사한 number변수를 통해 결국 둘 다 다른 메모리 공간을 차지하게 된 별개의 존재이기 때문에 number의 값 변화에도 num에는 아무 영향이 없음을 알 수 있었다.


Call By Reference의 예제도 살펴보자.
let arr = [10, 20, 30, 40, 50];
const updateArray = (arr) => {
    arr[0] = 100;
}
updateArray(arr);
console.log(arr);
// [100, 20, 30, 40, 50]

arr라는 배열을 updateArray 메서드의 인자로 넘겨주어 배열 내 원소값을 변경하였다. 메서드 실행 종료 이후 arr의 값을 출력해보면 첫번째 원소값이 변경되었음을 알 수 있다.

결국 arr이 가지고 있는 배열의 참조값을 가지고 메서드를 실행하였기 때문에 원본값에 변경이 발생한 것이라고 생각해볼 수 있다.

인자로 전달되는 변수가 원시값이라면 Call By Value로 처리되고, 원시값이 아니라면 Call By Reference대로 처리됨을 확인해볼 수 있었다.

결국 원시타입의 경우 우리가 알고 있듯이 값이 복사되어 전달되고 참조타입의 경우는 메모리 주소의 값(참조값)이 복사되어서 전달되기 떄문에 동작 원리는 같음을 인지하고 사용하자.



미들웨어(Middleware)의 중요성

수업중 알게된 미들웨어라는 용어는 광범위한 용어로 느껴졌는데, 이번 기회에 제대로 알아보려 한다.

미들웨어(Middleware)의 사전적 의미
미들웨어는 양 쪽을 연결하여 데이터를 주고 받을 수 있도록 중간에서 매개 역할을 하는 소프트웨어, 네트워크를 통해서 연결된 여러 개의 컴퓨터에 있는 많은 프로세스들에게 어떤 서비스를 사용할 수 있도록 연결해 주는 소프트웨어를 말한다. 3계층 클라이언트/서버 구조에서 미들웨어가 존재한다. 웹 브라우저에서 데이터베이스로부터 데이터를 저장하거나 읽어올 수 있게 중간에 미들웨어가 존재하게 된다.

이해한 내용을 간단하게 설명하자면 미들웨어는 결국 클라이언트-애플리케이션 서버 연결에 도움을 주는 역할을 수행하며, 클라이언트와 서버 사이에서 매개체로써 클라이언트/미들웨어/애플리케이션 서버 즉, 3계층을 이루고 있다.

미들웨어의 필요성

그렇다면 미들웨어를 도입하여 챙길 수 있는 이점들은 무엇이 있을까?

먼저 비즈니스 로직을 서버 단에서 관리하기 때문에 개발자 입장에서는 유지보수가 간편하다. 수정사항이 있다면 단순히 서버 단에서의 수정작업만 진행하면 되기에 유지보수가 쉽다.

그렇지만 사용자의 요청이 동시다발적으로 쌓이게 되면 결국 서비스에 부하가 발생한다. 사용자의 요청에 대한 프론트엔드의 정적 리소스를 처리하는 서버와 백엔드의 동적 리소스를 처리하는 서버로 분리하여 관리한다면 보다 효율적인 서비스를 제공할 수 있을 것이다.




Final..

JavaScript를 통해 데이터를 가져오고 화면에 출력하는 실습을 통해 전에는 어떤 흐름인지, 어떤 원리로 동작하는지 잘 알지 못했던 지식적인 내용들을 머릿속에서 나름대로 정리할 수 있었다.

그리고 홀로 과제를 수행하기보다는 동료들과 함께 과제를 수행하며 서로서로 코드 리뷰도 하고, 구현 결과에 대한 각자의 의견을 공유할 수 있는 환경을 마련할 수 있어서 뜻깊은 한 주 였다.

이러한 모임 환경을 지속적으로 유지하기 위해선 먼저 내가 잘 알고 있어야 하기에 공부에 대한 동기부여도 즉각즉각 생기고 동료에게 올바르게 전달하고 알려주기 위해선 다양한 리소스들 중에서 올바른 내용들만 잘 숙지하여야 한다고 느꼈다.



혹여 잘못된 내용이 있다면 지적해주시면 정정하도록 하겠습니다.

참고자료 출처

profile
찍어 먹기보단 부어 먹기를 좋아하는 개발자

0개의 댓글