여기서 의문이 시작됐다. JavaScript에서 Object와 Map은 어떻게 이루어져있을까?? 물론 인터프리터, 컴파일러, 엔진에 따라 다르겠지만,내가 자주 쓰는 Node를 기준으로 어떻게 되어있는지 궁금했다. 이에 대해 개인 Notion에 러프하게 정리했었는데, 블로그에 깔끔히 정리해보려한다.
Map과 HashMap
먼저 Map과 HashMap에 대하여 알고 있어야 이해하기가 편할 것 같다.
HashMap = unordered Map
HashMap은 key 와 value 를 hash 알고리즘에 의해 구현
Hash 알고리즘으로 넣으므로 전체가 어떤 특정한 규칙으로 정렬이 되어 있지 않다.
hash_map은 find에 이상적으로 O(1)의 시간을 소요한다.
하지만 hash_map은 실제로는 hash table의 크기에 반비례하는 O(n)의 시간을 소요한다.
예를 들어 1000개 저장하는데, 테이블 크기가 100이라면, 시간은 10만큼 걸릴 것이다.
Map ( Tree Map ), Ordered Map
Map( Tree Map)은 보통 red-black tree 알고리즘을 이용하여 구현
Tree의 규칙대로 들어가므로, Order되어 있다, 즉 정렬되어 있다.
Map( Tree Map )을 쓰는 경우, 최악의 경우 O(n), 최상의 경우 O(logn)의 시간복잡도
동일 출처 정책(same-origin policy)은 어떤출처에서 불러온 문서나 스크립트가 다른 출처에서 가져온 리소스와 상호작용하는 것을 제한하는 중요한 보안 방식입니다. 동일 출처 정책은 잠재적으로 해로울 수 있는 문서를 분리함으로써 공격받을 수 있는 경로를 줄여줍니다.
간단하게 설명하자면 a.com이라는 사이트에서는 a.com에서만 정보를 가져올 수 있다는 것이다. 즉 프론트 서버는 a.com으로, 백앤드 서버는 b.com으로 분리하면 안되고, 둘 다 a.com에 존재해야 데이터를 주고 받을 수 있다는 것이다.
교차 출처 리소스 공유(Cross-Origin Resource Sharing,CORS)는 추가 HTTP 헤더를 사용하여, 한출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제입니다. 웹 애플리케이션은 리소스가 자신의 출처(도메인, 프로토콜, 포트)와 다를 때 교차 출처 HTTP 요청을 실행합니다.
즉 간단하게 말하면, HTTP 헤더에 정보를 추가하여, 다른 Origin끼리도 데이터를 주고 받을 수 있게 한다!라는 것이다.
a.com에서 b.com의 데이터를 요청한다면,
클라이언트에서 서버로 요청할 때 http header에 { Origin : a.com } 이렇게 요청하는 곳의 출처를 넣고,
서버에서 클라이언트로 응답할 때는 { Access-Control-Allow-Origin : 허용할 주소 } 이렇게 응답을 보낸다.
그리고 만약 내가 요청한 주소가 허용할 주소에 포함되어 있다면, 데이터를 받아서 화면에 뿌려준다.
그렇지만 반대로 요청한 주소가 허용할 주소에 포함되어 있지 않다면, CORS 오류가 발생한다.
CORS 오류 해결 방법
이 문제를 해결하기 위해서는 서버 측에서 응답할 때 http header 내에 있는 {Access-Control-Allow-Origin : 허용할 주소}에 a.com을 넣어주면 CORS 오류는 발생하지 않게 된다.
혹은 어느 사이트에서 요청할지 모르니, {Access-Control-Allow-Origin : *} 로, 모든 주소를 허용하면 편하게 해결할 수 있다. 물론 이렇게 된다면 보안상 문제가 생길 수 있다.
만약 내가 서버를 건들일 수 없다면, 이 문제는 브라우저에서 막아서 발생하는 문제이므로, 프록시 서버를 하나 만들어서, 프록시 서버에서 정보를 받아온 후, 클라이언트에 {Access-Control-Allow-Origin : 허용할 주소}를 허용하여 문제를 해결할 수 있다.
이 부분은 시간이 되면 그림과 함께 자세히 다루어보려고 한다.
그리고 클라이언트 쪽에서 문제를 해결하는 방법을 찾아보려한다.
CORS의 보안 문제?? 어디가??
사실 이 윗부분은 CORS를 구글에 검색하면 나오는 보편적인 내용이다. CORS를 검색하면 가장 위에 나오는 MDN을 한 번 읽어본기만 해도 이해할 수 있는 내용이다. 만약 이 글이 이해가 안된다면, MDN에는 친절하게 그림과 함께 설명되어 있고, 친절하게 설명되어 있는 블로그들이 많다.
하지만 이 글을 적게 된 이유는 나처럼 이 글들을 읽고 이해가 안되는 부분이 있는 사람이 있을 것 같아서이다.
내가 이해가 안되는 부분은 보안상 문제라는 부분이었다.
처음에 나는 보안상 문제라고 하여,
허가 받지 않은 클라이언트가 서버의 정보를 몰래 빼오려고 요청하는 것을 막는 것인줄 알았다.
API를 만들어서 내 사이트에만 뿌리고 싶은데, 다른 사용자들이 맘대로 가져가서 사용하려고하는 것을 막으려는 건 줄 알았다.
하지만 이렇게 이해를 하면 막히는 부분이 생긴다.
서버에 정보를 요청하면 정보는 보내주지만, 단지 http header에 {Access-Control-Allow-Origin : 허용할 주소} 를 넣어서 보내고,
이 http header를 클라이언트의 브라우저에서 확인한 후, 자신이 허용할 주소가 아니라면 정보를 클라이언트에게 보여주지 않는 것이다.
서버에서 정보는 잘 보내줬는데 클라이언트에서 막을까?라는 생각과 내가 생각한 보안 문제가 아닐 것이라는 의심을 하였다.
그리고 그 이유를 찾아보았고, 맞는지는 모르겠지만 어느 유튜브에서 그 이유를 들을 수 있었다. 유튜브의 출처는 글 맨 하단에 작성하였다.
내가 알게된 CORS 정책의 이유를 예시를 들어서 설명하면,
내가 서비스를 만들었는데, a.com이라는 사이트를 만들고, b.com이라는 WEB API를 만들었다고 가정하자.
a.com에서는 로그인 한 후, 그 정보를 이용하여 b.com에서 데이터를 가져올 수 있다.
이런 상황에서 Trudy라는 정보를 탈취하고 싶은 사람은 t.com이라는 나쁜 사이트를 만들었다.
t.com에 사용자가 접속하면, b.com으로 정보를 요청해서 받아온다.
이 때, 클라이언트에 저장되어 있는 쿠키 같은 정보를 이용하여 사용자가 로그인되어 있는 상태로 요청하여 정보를 캐올 수 있다.
이 때 b.com에는 a.com만 허용하는 CORS 설정을 해놓았다면,
t.com에서 b.com으로 요청해서 받아오는 정보는 CORS 오류가 발생하게 되어 t.com한테 정보를 탈취당하지 않을 수 있다.
맥락과 흐름이 이렇게 이루어져, CORS는 이런 보안을 위하여 존재하는 정책이고,
이 부분도 시간이 난다면 그림과 함께 자세하게 설명하겠다.
[회고] CORS에 대한 공부를 하고,,,
CORS에 대해 공부를 하며, 생각보다 보안의 의미가 크고, 글을 읽으며 내가 네트워크 보안이라는 과목을 듣지 않았다면 이해를 한 번에 할 수 없었을 것이라 생각이 들어, 전공에 대한 기초 지식의 중요성을 느꼈다...
그리고 문제를 해결할 때, 문제가 해결되었다고 끝내는 것이 아니라, 해결할 때 들었던 의문점들을 제대로 해소해야되겠고, 왜라는 의문을 더 깊게 해야되겠다는 생각이 들었다.
공채 공고가 나왔을 때, 내가 너무 바빠가지고, 자소서를 쓸 시간이 없었는데, 다행히도 쿠팡은 카카오처럼 1차는 자소서가 없이 코테만 보기에 바로 신청했다.
추첨을 통해 기념품? 같은 것도 준다고 했는데, 연락이 없는 것을 보면 당첨이 되지 않은 것 같아서 슬프다....
코딩 테스트는 다른 기업들처럼 프로그래머스라는 플랫폼에서 봤고, 코드 복사는 되지 않아서, 알아서 스페이스바와 탭을 쳐주어야했다..
네이버도 그렇고 쿠팡도 그렇고 외부 복사 막는 것은 이해가 되나, 코드 복사를 하지 않으면 인덴트가 너무 어렵다... ㅠㅠ
C언어나 C++ 같은 경우 프로그래머스에 내장된 vim으로 명령어를 입력하면 인덴트가 되는데, JS는 지원을 안하는 건지 내가 모르는건지, 되질 않아서 한땀한땀 스페이스 바를 쳐줬고, 어떨 때는 컨벤션이 기억이 나지 않아, 내 vscode에 입력한 다음, 정렬된 코드를 한땀 한땀 손으로 쳤다... 물론 이래도 모든 부분을 완벽하게 하지는 못했다 ㅠ
문제의 난이도는 그렇게 어렵지는 않았다. 시간은 3시간에 총 4문제가 나왔고, 모든 문제를 다 풀었고! 시간이 많이 남아 리팩토링과 반례도 넣어보았다.
한 문제 빼고는 다들 30분 이내로 풀었던 것 같다. 그리고 그 문제도 알고리즘적으로 어렵다기보단 구현할 때 고려해야할 사항들이 많아서 어려웠다.
근데 살짝 걱정되는 부분은 테케를 많이 주지 않아 잘 돌아가나 싶었고, 괜히 리팩토링해서, 제대로 짠 코드를 망치지 않았나라는 걱정도 들었다.
요즘 이렇게 알고리즘 문제를 풀 때 드는 생각은, 예제 넣고 결과가 나오고, 그걸로 코드가 잘 짜여진거구나 확인하는 이 방식이 바로 TDD가 아닌가 싶다 ㅋㅋㅋ 테케가 많으면 리팩토링하거나 새로운 기능과 함수를 추가해도, 내가 제대로 짠 건지 알 수 있으니까.... 이런 생각이 드니까 TDD를 공부하고 프로젝트에 적용시키는 것에 익숙해지면, 프로젝트가 훨씬 편하고 견고해질 수 있을 거라는 생각이 들었다.
잡담은 여기까지고, 이번에도 문제는 다 JS로 풀었다.
사실 중간중간 많이 고민했다.
C++이나 Python 같은 언어로 풀면 제공하는 자료 구조가 있었고, 그 자료 구조로 풀면 훨씬 쉽고, 효율성도 좋아지기에 다른 언어를 사용해야하나 고민했다.
그리고 잘못짜면 스택오버플로우가 일어날 수 있는 문제가 있었는데, JS의 기본 스택 크기가 어느 정도 되는지 몰라서 너무 걱정이 되었다.
찾아보니 프로그래머스는 Node 12 버젼 환경이고, 이 버젼의 default 값으로는 터지지 않을 것 같았지만, 그래도 불안했기에 다른 언어로 짤까 많이 고민했다.
하지만 JS로 풀기로 마음 먹었고, JS로 풀면 효율성은 몰라도, 코드는 더 깔끔하게 짤 자신이 있기에 JS를 선택해서 모든 문제를 JS로 풀었다.
JS으로 함수 단위로 코드를 짜서, 함수형 프로그래밍을 하면 깔끔하게 짤 수 있기에, JS로 짰다. 그리고 좀 복잡하고 긴 문제가 있었는데, JS로 풀었기에 이 문제에서 시간을 많이 잡아먹지 않았던 것 같다. 물론 다른 언어 쓸까 고민을 많이하느라, 그 부분에서 시간을 많이 잡아먹었다.
그리고 사실 함수형 프로그래밍이라기엔 많이 부족하고, 그냥 함수로 나누어서 짜고, 순수 함수를 지향했지만, 배열이나 객체는 프로그래머스 사이트 내에서 코딩을 해야하는게 익숙하지 않아, 괜히 실수할까 좀 불안해서 그렇게 하지 못한 점이 좀 아쉽다.
이렇게 함수 단위로 나눌 수 있다는 점에서 자바스크립트나 파이썬은 프로그래머스 같은 solution으로 입출력을 받는 플랫폼에서 함수형으로 깔끔하게 짤 수 있어서, 코딩테스트할 때 좀 유리한 것 같다. 물론 자바스크립트는 자바나 C++, 파이썬 같은 언어보다는 제공하는 자료 구조가 너무 없긴 하지만,,,이래서 다들 파이썬 파이썬 하나보다..
한 문제 빼고는 코드 길이도 길지 않았고, 매직 넘버나 매직 스트링을 따로 선언해주거나, 변수명을 의미 있게 짓는 등 노력도 많이 했으니 결과만 기다려야겠다.
다만 자바스크립트로 짜느라 효율성을 조금 포기한 부분이 없잖아 있어 그 점은 조금 불안하긴 하다.
진짜 문제를 다 풀어도 불안하고 뭔가 찜찜하고 아쉬운 것 같다... 대체 언제쯤 풀고나서 만족스럽게 나는 합격이다!라는 생각이 들까? ㅋㅋㅋ..ㅠ.ㅠㅠㅠ
아주아주 잘하시는, 예를 들어 코드포스 레드이신 분들은 그런 생각이 들려나..?
그래도 이번 코테를 보며, 알고리즘 실력은 모르겠지만, 구조화하는거나, 함수를 나누는 것 등 코드 짜는 실력은 많이 늘은 것 같다. 내가 짜놓고 나름 깔끔하게 잘 짰다는 생각이 들었다. 물론 예전에 비해서 많이 늘은거지, 아직 발전해야할 부분이 많다.
확실히 계속하다보니, 깔끔하게 하면서도 빠르게 짜게 되었고, 이런 습관은 코드를 짜다가 중간에 헷갈리거나, 꼬이는 부분을 방지해서, 문제를 안정적으로 풀 수 있게 해주는 것 같다. 자바스크립트 실력을 계속해서 늘려서, 앞으로 코테 다 자바스크립트로 뿌시리라!! 그리고 취뽀까지 파이팅!!!