# 기술 면접 질문 ###### tags: `Etc` ## Front End ### CSS Rendering #### 1. Critical Rendering Path 1. 처음으로 HTML 파일을 받아 Tokenizer, Lexing 과정을 거쳐 `DOM 트리`를 생성합니다. 이 때 동시에 스타일 시트를 받아와 `CSSOM`을 생성합니다. 2. 만들어진 DOM과 CSSOM으로 `Render Tree`를 만드는 `Style` 과정을 거칩니다. 이 때, Render Tree는 화면에 보이는 요소의 위치와 크기를 계산하는데 사용되기 때문에 `display: none` 이 적용된 요소들은 트리에 포함하지 않습니다. 3. 그리고 `Layout` 과정을 거쳐 Render Tree 노드들의 정확한 위치와 크기를 계산합니다. 이 때, %를 px로 변환하는 등 정확한 값들을 계산합니다. 4. 그 다음으로 위치와 관계 없는 색상, 투명도 같은 속성을 적용하는 `Paint` 과정을 거치고 화면에 픽셀 단위로 그립니다. #### 2. CRP 최적화 1. 첫 번째로, HTML에 필요한 파일들을 서버에 요청하는 횟수를 줄입니다. 이미지 같은 경우 스프라이트를 만들어 하나의 페이지에 사용되는 이미지들을 합친 파일을 제공해 `background-position` 속성을 사용해 적용합니다. 또한, js나 css파일을 번들링해서 한개의 파일로 사용하게 합니다. 2. 두 번째로, 파일 크기를 줄이는 것입니다. 기본적으로 배포를 할 때 웹팩의 minify 플러그인을 사용합니다. 3. 세 번째로, 초기 렌더링 최적화를 합니다. CSSOM이 구성될 때까지 Render Tree가 만들어지지 않습니다. 또한, CSSOM 생성은 DOM 파싱을 방해하지 않기도 하며, 하지만 HTML 파싱 중, link를 만나면 스타일시트 파일을 받을 때까지 Blocking됩니다. 그리고 스크립트에서 잘못된 스타일에 접근을 할 수 있어 `<head>` 태그 안에서 모두 로드를 합니다. 또한 환경에 따라 미디어 쿼리를 사용해 불 필요한 Blocking 을 방지합니다. 4. JS는 HTML 파싱을 Block하기 때문에, `<body>`의 끝 부분에 로드하거나 지연 로드를 합니다. #### 3. Reflow와 Repaint 렌더링은 style, Layout, Paint, Render를 거치면서 수행됩니다. DOM이나 CSSOM 노드의 높이 같이 다른 요소들에 영향을 주는 속성이 변경되었을 때 Layout 과정을 거치면서 Render Tree의 모든 값들이 재계산됩니다. 하지만 color, text-decoration 등 다른 요소에 영향을 주지 않는 속성의 변경은 Paint 과정만 거치게 됩니다. Reflow와 Repaint 둘다 Paint 과정을 거치지만 Reflow는 Layout 과정으로 값들을 재계산하면서 부하가 크기 때문에 상대적으로 적용 시간이 더 오래 걸립니다. #### 4. Reflow 최적화 1. 우선 Layout 회수를 줄이는 것입니다. 대표적으로 `offsetWidth`속성을 사용할 때마다 Layout 과정을 통해 값을 계산합니다. 그래서 이 속성 값을 하나의 변수에 저장하고 로직을 구성해 Layout 수행을 줄입니다. 2. 두 번째, 다른 요소에게 주는 영향을 줄입니다. DOM의 상위 노드가 Layout을 수행하게 되면 하위 노드에 영향을 주는데, 만약 부모 요소의 높이가 가변적일 때 자식 요소의 높이가 변경되면 부모 요소에 Layout이 발생하면서 자식 요소들에게도 Layout이 발생하며 부모의 형제 요소들에게도 영향을 줍니다. 따라서, 부모 요소의 높이를 고정을 시켜 Layout 범위를 줄입니다. 3. `display: none`의 요소는 숨긴 상태에서 속성을 변경시켜줍니다. `display: none` 노드는 Layout과 Repaint 과정을 거치지 않기 때문입니다. 4. 애니메이션을 적용한 노드의 position을 absolute로 지정합니다. 그렇게 되면 주변 영역에 영향을 주지 않게 됩니다. ### 이벤트 위임 #### 이벤트 버블링 이벤트 버블링은 이벤트가 발생했을 때 자식 요소에서 조상 요소까지 전파되는 현상입니다. #### 이벤트 캡쳐링 이벤트 캡쳐링은 이벤트가 부모 요소에서 자손 요소로 전파시키는 현상으로, `addEventListener`의 세번째 인자 객체에 `capture: true`를 넣어주면 적용이 됩니다. #### 이벤트 위임의 정의와 장점 요소들마다 이벤트를 정의하지 않고 해당하는 요소들의 부모 요소에 이벤트를 등록하고 그 이벤트 리스너에 조건을 주면서 적용하려 했던 요소들의 이벤트 효과를 주는 것입니다. 이런 기법의 장점으로 다수의 이벤트를 하나의 이벤트로 처리하기 때문에 메모리를 좀 더 확보할 수 있게 됩니다. ## BackEnd ### Redis - Redis 소개 - Redis 내부 구조 - Redis 사용 수단 - Redis 운영 중 하면 안될 것 - Redis Cluster - Redis Sentinel - Redis Pub/Sub ### MSA 1. MSA란 MSA는 하나의 프로젝트를 작은 단위로 서버들을 나눈 아키텍처입니다. 보통 모놀리식 아키텍처와 비교가 됩니다. 모놀리식 아키텍처는 하나의 프로젝트자체가 단위가 되기 때문에 분산처리란 개념은 선택적이고 서버 Cluster, DB Cluster에만 속합니다. 하지만 MSA는 각 서비스를 하나의 서버로 두기 때문에 처음부터 분산처리를 기반으로 시작합니다. 또한 서비스가 정해진 기준을 단위로 나뉘어졌기 때문에 부분적인 스케일 아웃이 가능합니다. 그리고 각각 의존성이 적기 때문에, 하나의 서비스에 장애가 발생해도 다른 서비스들에게 영향을 주지 않습니다. 2. 아키텍처에서 서버를 나누는 기준 저희는 프로젝트가 절대적으로 보았을 때 크다고 생각하지 않았고 서비스 관점에서의 확장성을 고려할 필요가 없다고 판단했습니다. 그래서 앞으로의 확장성을 생각하면 작은 단위로 서비스를 설계하는 것이 맞지만, 퀄리티면에서 내부 통신간의 데이터 유실을 고려하면 API 호출 빈도가 적은 것을 신경을 쓰는 것이 맞다고 판단했습니다. 그래서 첫번째로, 프론트의 페이지 구성과 서비스 흐름도를, 두번째로 DB 컬렉션 스키마를 이용했습니다. 그래서 각 페이지에서 요청하는 API에서 응답을 원하는 것들을 정리하고, 컬렉션 스키마들을 비교하면서 필요한 부분에 선을 그으면서 Top-Down 방식으로 나누고 자원의 의존성을 유지하는 방향으로 진행했습니다. 3. 사용했던 설계가 과연 부합했을까? 이 주제로 많은 생각을 했지만 아직도 답을 내리지 못한 상태입니다. MSA에서 가장 어렵다고 생각하는 부분이 서비스를 설계하는 것이였습니다. 왜냐하면 잘게 나누어 의존성이 작은 설계와 서비스간의 API 호출 수, 이 두 개는 Trade Off 관계라 명확한 판단하기 어렵습니다. 또한, 공유 자원까지 고려해서 아키텍처를 설계하면 생각할 것이 많기 때문입니다. 그리고 사람들의 가치관이 다르기 때문에 어렵습니다. 예를 들어 쇼핑몰을 주제로 기획했을 때 구매 버튼으로 이루어지는 서비스와 장바구니 버튼으로 이루어지는 서비스가 하나의 거래 서비스로 둘지, 각각의 서비스로 둘지 딱 정할 수 없기 때문입니다. 그래서 이런 문제는 팀원들의 성향도 중요해서 그때그때마다 다를 것 같습니다. 4. MSA의 장단점 제가 생각하는 MSA의 장점은 트래픽 분산인 것 같습니다. 처음부터 서비스들이 나누어져있는 상태이기 때문에 트래픽의 스트레스의 한도가 높아집니다. 수치적으로 기억이 나지 않지만 실제로도 스트레스 테스트할 때 많은 트래픽에서도 서비스가 유지가 되었던 기억이 있습니다. 그리고 서비스들간의 장애 전파가 없다는 것입니다. 실제로 검색 서비스 서버를 종료해도 스터디 그룹 정보를 확인할 수 있고 예약과 결제가 되었습니다. 그리고 단점으로는 규모가 있는 서비스외엔 관리가 어렵다는 것입니다. 저희가 MSA를 채택할 때 가장 눈에 띈 것은 프로젝트 관리가 편해진다는 것입니다. 하지만 서비스라는 단위마다 관리를 해야하니까 CI/CD는 물론, 프로젝트 관리가 어려웠습니다. 아마 이 장점은 어느정도 규모일 때 성립한다고 생각이 들어 적당선의 프로젝트는 모놀리식 아키텍처가 관리가 편할 것이라고 생각합니다. 또한, 서비스 간의 통신 문제에 대해서도 고려할 것이 많고 서비스간 데이터 유실을 고려해야 하는 복잡성이 있습니다. 5. MSA 내부 통신의 데이터 유실 문제 해결 방법 저희는 데이터 유실 문제를 해결하기 위해 각 서비스마다 Redis로 Job Queue를 구현했습니다. 예를 들어 사용자가 스터디 그룹을 가입하게 되면 스터디 그룹 DB에 해당 그룹의 참여자 배열에 push를 한 뒤, 다른 서비스인 사용자 서비스에서 DB에도 사용자의 참여 그룹 배열에 push를 해야했습니다. 이 때, 데이터가 유실되는 문제는 중간 서비스의 다운으로 판단했습니다. 그래서 소켓은 상대방의 다운을 감지하는 것을 이용해서 다음 서비스로 데이터를 전달할 때 해당 서비스의 Job Queue에 push를 했습니다. 그래서 다운된 서버를 가동했을 때 먼저 Job Queue의 내용을 처리하게해 나중에 생기는 데이터 불일치성을 방지했습니다. 서버 가동 중일 때 오류가 발생하면 바로 API Gateway에게 오류 의미가 담긴 데이터를 전달을 하게 됩니다. 하지만 구체적인 에러 처리 로직을 처리하지 못했습니다. ## JavaScript ### Immutable과 Mutable 무엇인가? Immutable은 객체의 상태를 변경할 수 없는 것을 말합니다. 그리고 Mutable은 이와 반대되는 개념입니다. 객체는 Reference 형태로 이용되는데, 객체의 참조가 공유되어 있는 변수를 통해 상태가 변경되면 참조된 변수가 변경됩니다. 이런 특성은 의도치 않은 동작으로 이어지는 위험이 있습니다. 그래서 함수형 프로그래밍이나 Redux에서 사용되는 패턴에서 객체 자체를 변경하는 것이 아닌 새로운 객체를 할당해주는 방향으로 Immutable한 방식을 사용합니다. ### Execute Context란? 엔진이 코드를 실행하기 위해 필요한 정보들이 있는 환경입니다. Context는 보통 함수 단위로 구성되는데, 하나의 Context마다 변수의 정보를 가진 Variable Object와 중첩된 함수의 Scope 레퍼런스를 차례로 저장한 리스트인 Scope Chain, 함수의 호출패턴을 가리키는 this를 가지고 있습니다. Scope chain의 요소들은 각각 Scope에서 접근하는 Variable Object를 가리킵니다. ### 호이스팅이란? 임의의 Scope에서 변수나 함수가 선언되기 전에도 접근할 수 있는 것을 말합니다. 엔진은 Context를 만들기 위해 코드를 실행하기 전에 탐색 과정을 거칩니다. 그 과정에서 함수나 var 변수의 이름을 가지게 되면서, Scope에서 변수나 함수를 선언하기 전에서도 접근할 수 있게 됩니다. 함수 선언식경우 이름뿐만 아니라 함수내용도 사용할 수 있지만 var 변수는 이름만 접근할 수 있으며 값이 할당되어 있지 않습니다. #### const와 let은 호이스팅되나요? const와 let은 호이스팅이 되지만 호이스팅으로 원하는 결과가 나오지 않습니다. 호이스팅은 Context를 만들기 위해 탐색하는 과정에서 변수와 함수를 인식합니다. 그 과정에서 var 변수나 함수 선언식은 이름을 기록하면서 메모리에 공간을 확보하지만 const와 let은 이름을 기록할 뿐 메모리에 할당하지 않습니다. 이 때문에 선언문 전에 접근할 수 없으며, 선언식이 실행되어야 메모리에 할당이 됩니다. ### 클로저란? 함수가 속한 Lexical Scope를 기억해 함수가 Lexical Scope 밖에서 실행될 때도 이 Scope를 접근하는 기능입니다. 이 기능으로 Lexical Scope 밖에서 사용된 함수는 선언된 함수 외부 Scope의 변수나 함수를 접근할 수 있는데, 이것은 엔진의 Garbage Collector가 Lexical Scope의 변수와 함수 참조를 인지하기 때문에 접근할 수 있는 것입니다. ### Lexical Scope란? 코드를 작성할 때 함수를 어디에 선언하는지에 따라 정의되는 Scope입니다. 함수들은 Lexing 과정을 거쳐 의미를 부여하는데, 이 과정에서 생성된 Scope입니다. ### This란? this는 함수 호출자로 Execute Context 즉, 코드 블록이 실행되는 환경을 말합니다. this는 사용되는 함수 자체를 가리키는 객체가 아닌, 자신이 속한 Scope의 함수를 호출하는 대상자를 가리키게 됩니다. 또한, this는 Lexical Scope를 가리키는 레퍼런스도 아니고 오로지 함수를 호출한 코드에 따라 동적으로 달라집니다. ### This binding 우선순위 this Binding의 우선 순위는 차례대로 new Binding, 명시적 바인딩, 암시적 바인딩, 기본바인딩이 있습니다. new Binding은 객체의 인스턴스를 만들 때 사용되는데, 이 때 함수내에 빈 객체를 만들어 지고 this가 이 객체에 바인딩됩니다. 명시적 바인딩은 apply, call, bind 메서드를 통해 this를 고정적으로 바인딩을 하는 것입니다. 암시적 바인딩은 객체가 메서드 호출 시, 바인딩 되는 것으로, 호출 객체가 binding됩니다. 기본 바인딩은 전역함수가 호출될 때 전역 객체가 this로 binding 되는 것입니다. ### Garbage Collector 사용되지 않는 변수가 메모리에 해제되는 과정을 Garbage Collection이라고 하는데, 이를 관리하는 것이 Garbage Collector라고 합니다. JS의 GC 알고리즘은 Reference Counting과 Mark Sweep이 있으며 최신 브라우저는 후자를 사용하는 것으로 알고 있습니다. - Reference Counting은 객체를 참조하는 대상이 하나도 없는 경우에 해제 대상으로 정합니다. 하지만 객체가 A, B가 있다고 했을 때, A의 속성 값으로 B를 가지고 있고, B 속성 값으로 A를 가지고 있을 때 순환 참조 문제가 발생하는데 GC의 대상이 되지 못하는 문제가 발생합니다. - Mark Sweep은 객체가 필요한지 여부를 해당 객체에 접근할 수 있는지로 판단합니다. 그래서 전역 객체에서부터(Root set) 참조하는 객체들을 대상으로 차례대로 자식이 되는 트리 형태의 자료 구조를 가지면서 접근하지 못하는 레퍼런스들에 대해 메모리를 해제합니다. ### Prototype이란? 객체마다 별도로 연결되어 있는 또 다른 객체입니다. 보통 JS에서 객체지향 프로그래밍을 사용할 때 필요한 개념입니다. A 객체의 prototype을 B로 Linking하면 A는 B의 자식이 되는데, 이는 위임이라고 불리는 상속의 개념입니다. #### `__proto__` 와 prototype의 차이 `__proto__`는 객체의 Prototype Object으로, 객체의 Constructor의 prototype을 가리킵니다. 하지만 prototype은 함수 객체만 가지고 있으며, 이 객체로 생성자를 만들었을 때 객체와 연결된 prototype Object를 가리킵니다. #### Prototype Chaining 과정 객체는 접근하려는 속성이나 메서드가 없으면 `__proto__`가 가리키는 링크를 따라 prototype Object에서 찾으려는 속성이나 메서드를 봅니다. 만약 없을 경우 prototype Object의 `__proto__`를 찾아가며 이 과정을 Object까지 실행되어야 멈춥니다. #### DOMContentLoaded와 load의 차이 DOMContentLoaded는 HTML 문서가 로드되고 HTML 파싱으로 DOM 트리 생성이 완료되면 발생하는 이벤트입니다. load는 HTML 파싱 뿐만 아니라 CSS로 만들어지는 CSSOM, 이미지와 스크립트처럼 의존성 있는 리소스가 준비될 때 실행됩니다. ### 자신이 좋아하는 라이브러리가 무엇인가? 저는 함수형 프로그래밍을 좋아합니다. 그래서 lodash도 사용하지만 국내 마플의 오픈 소스인 fxjs로 함수형 프로그래밍을 공부를 했습니다. 왜냐하면 지연평가, 병렬처리별로 기능을 명확히 구분을 했고 기능이 다른 함수들을 파이프라인에 마음대로 조합해 사용할 수 있는 조립식 형태가 마음에 들었습니다. 또한, IE11까지 호환되는 기능으로 좀 더 크로스 브라우징에 신경을 쓴 점이 좋았습니다. ### 오픈소스에 기여하거나 특정 모듈의 내부를 살펴본 적이 있는가? fxjs 내부를 본 적이 있습니다. fxjs의 map, filter같은 함수들은 내장된 배열의 메서드와 달리 generator로 구현이 되어 있어, 함수들이 체이닝되어도 배열을 새로 만들지 않아 미미하지만 성능이나 메모리 관리면에서 더 성능이 좋습니다. 하지만 지연평가를 사용할 수 있어 좀 더 명확하게 성능을 높일 수 있습니다. generator로 구현되어 있어 파이프라이닝으로 로직을 짜게 되면 수평적이 아닌, 수직으로 처리할 수 있기 때문에 필요한 결과 개수를 명시하면 필요한 데이터 개수가 채워지면 불 필요한 로직을 수행하지 않게 됩니다. 그리고 모나드 이론을 잘 활용해서 중간에 catch문으로 발생한 에러를 중간에 없는 데이터로 처리하기 때문에 에러 발생을 줄일 수 있고 비동기 함수도 파이프라이닝을 지원하기 때문에 비동기 또한 순서대로 처리할 수 있습니다. ### 비동기를 처리하는 방법으로 무엇이 있나요? 콜백과 Promise, async await이 있습니다. 콜백함수는 API에게 데이터 처리를 위임함과 동시에 결과 값을 돌려주면서 실행할 함수를 같이 알려주는 방식입니다. 그래서 API에서 처리된 결과 값을 가진 함수는 이벤트 큐에 쌓아지고 Call Stack이 비어질 때 실행됩니다. Promise는 비동기 자체를 값으로 표현한 객체입니다. 콜백함수는 여러 개의 비동기 함수가 호출될 때 함수가 중첩적으로 사용되어 발생하는 가독성 문제를 해결하기 위해 then을 체이닝 방식으로 사용해 좀 더 깔끔한 코드를 처리할 수 있게 만듭니다. async await은 Promise를 동기적인 흐름으로 만들어줍니다. async를 사용한 함수는 내부적으로 Promise를 반환하게 만들며, 내부에서 호출된 Promise에 await을 붙여주면 해당 Promise가 값을 낼 때까지 다음 구문이 호출되지 않게 됩니다. ### Promise의 내부 원리를 아시나요? ### Async await의 내부 원리를 아시나요? ## Web ### Cors 클라이언트를 제공한 서버를 Origin으로 두면서 클라이언트가 Origin이 아닌 서버로 요청했을 때 거부시키는 정책을 없애주는 것입니다. 예전에는 클라이언트를 제공한 서버외의 요청은 잘못된 접근으로 판단해 막았습니다. 하지만 성능 개선 등의 문제로 외부 API 등을 사용하면서 이런 문제를 극복하기 위해 존재합니다. #### Simple Request Cors에 해당되는 요청 중 한번의 요청과 응답이 오가는 것을 말합니다. 이 요청이 발생하는 조건으론 GET, HEAD, POST 중 하나의 http 메서드이고 커스텀 헤더가 없어야 합니다. 만약 POST 방식의 요청이면 Content-Type이 application/x-www-form-urlencoded, multipart/form-data, text/plain 중 하나여야 합니다. #### Preflight Request Simple Request가 아닌 요청들을 말합니다. 데이터를 요청하기 전에 OPTIONS 메서드의 데이터를 요청한 뒤, 서버에게 `access-control-xxx`의 필드가 포함된 응답을 받은 뒤, 지금 보낼 요청이 적절한지 판단하여 서버에게 요청합니다. #### Same Origin Policy를 해결하는 방법 JSONP와 Access-Control-Allow-Origin을 설정하는 방법이 있습니다. JSONP는 script 요소의 요청이 보안 정책에 위반되지 않는 것을 이용한 방식입니다. 하지만 GET 방식 용도로만 사용이 가능합니다. Access Control Allow Origin은 서버측에서 설정하는 솔루션입니다. origin과 method, credential 등의 헤더 필드들을 설정해 클라이언트에게 응답하는 방식입니다. ### 객체지향 설계 #### OOP를 설계하는데 중요한 원칙을 아시나요? 제가 알고 있는 객체지향 설계에서 SOLID라는 원칙 5가지를 알고 있습니다. 이 원칙들을 사용해서 객체 내부의 응집도를 높이고, 객체 외부간의 결합도를 낮추는 것이 궁극적인 목표로 알고 있습니다. #### 왜 객체 내부의 응집도를 높이고 외부간의 결합도를 낮추는 것을 추구할까요? 프로젝트의 관리에 사용하는 인력을 줄일 수 있기 때문입니다. 제가 생각하는 소프트웨어 구성에 있어서 가장 중요한 것은 유지 보수라고 생각합니다. 무언가를 서비스할 때 기능을 시간내에 구현하는 것도 중요하다고 생각하지만, 미래를 보았을 때 수정을 용이하게 하는 것이 확장면에서 보다 손실을 줄여주기 때문입니다. 그런 면에서 재사용성을 높이고 수정을 최소화하는 것이 기능을 추가할 때나 수정할 때 접근해야하는 영역이 줄어들기 때문에 손실을 줄여주는 기대효과가 생긴다고 생각합니다. #### Solid가 무엇인지 간단하게 설명해주실래요? 1. 첫번째로 단일 책임 원칙이 있습니다(SRP). 이 원칙은 객체의 책임을 최소화해 수정과 보완할 것을 줄여줍니다. 2. 두번째로 개방 폐쇠 원칙입니다(OCP). 임의의 객체에 대해서 내부에서만 사용하는 기능 수정에는 관대하지만 외부 객체와 의존하는 기능은 interface 등을 사용해 제한하는 것입니다. 3. 세번째로 리스코프 치환 원칙입니다(LSP). 부모와 자식간의 관계를 논리적으로 잘 풀어서 설계하는 원칙입니다. 즉, 상속을 통해서 확장을 하기 때문에 자식 객체의 Upcasting이 문제가 없어야 합니다.(아버지<->아들 x, 포유류 <-> 고래 o) 4. 네번째로 인터페이스 분리 원칙입니다(ISP). 각 객체의 역할에 필요 없는 것을 줄여주기 위해, interface로 책임 단위를 최소화시키고 객체마다 필요한 책임들을 묶는 것입니다. 5. 다섯번째로 의존성 역전 원칙입니다(DIP). 상위 클래스가 하위 클래스를 의존하면 안된다는 것입니다. 왜냐하면 하위 클래스일수록 사용이 많아지고 그에 따라 변화가 많아집니다. 그렇게 된다면 하위 클래스가 변화할 때마다 상위 클래스의 수정될 필요가 많아집니다. #### Solid에서 가장 중요하게 생각하는 원칙이 무엇인가요? 저는 단일 책임의 원칙이 가장 중요하다고 생각합니다. 왜냐하면 다른 원칙들에 근본이 되는 원칙이기 때문입니다. 객체지향은 객체를 주체로 설계를 합니다. 각 객체는 다른 객체와 상호작용을 하는 것을 염두로 프로그래밍을 이끕니다. 그래서 각 객체간 의존성을 필요로 합니다. 하지만 한 객체당 영향을 주는 객체가 많아지면 내부적인 흐름이 어려워지면서 복잡도가 증가하게 됩니다. 그래서 이런 복잡도를 줄이기 위해 각 책임을 최소화 시키고 그것들을 작은 단위로 확장하게 된다면 필요없는 코드가 줄어들고 좀 더 코드 내에서 의존 관계를 확인할 수 있을 것 같습니다. ### 클라이언트의 요청에서 응답까지의 과정 1. 먼저 DNS를 통해 시스템 내에 있는 hosts 파일을 조회해 요청한 도메인의 ip가 있는지 확인합니다. 없으면 등록된 DNS 서버에게 ip 정보를 받아옵니다. 2. 그 후, 브라우저에선 http 프로토콜에 의거해 url을 파싱한 뒤, http header를 붙입니다. 3. 그리고 Transport Layer에서 TCP HandShake 과정으로 연결을 확립한 뒤, 4. Network Layer에서 경로와 관련된 정보를 IP에 의거해 헤더를 붙이고 5. Data Link Layer에서 당장 전달할 대상의 IP를 보고 MAC 주소를 확인합니다. MAC 주소를 모를 경우 ARP 프로토콜을 사용해 알아냅니다. 이런 과정을 거쳐 패킷이 서버로 이동합니다. 6. 그 과정에서 거치는 라우터들마다 라우팅 테이블을 참조해 경로를 알아가면서 도착하게 되고 7. 서버가 코드를 인식할 때까지 TCP/IP의 Layer들을 차례로 타고 올라가 패킷을 역캡슐화한 뒤, 클라이언트가 보낸 메세지를 확인하고 클라이언트에게 응답합니다. 서버에서 클라이언트로 가는 패킷도 앞서 말한 것들과 동일하게 이루어집니다. ### Session #### Cookie가 무엇인가? 상태가 없는 HTTP 프로토콜를 보완하기 위해 사용하는 데이터로, 서버로 요청할 때마다 참고하는 데이터입니다. 데이터는 클라이언트 컴퓨터의 메모리에 저장됩니다. 쿠키는 요청보낼 때마다 보내기 때문에 수가 많아지면 트래픽 용량이 커집니다. 또한, 보안성이 낮아 민감한 정보에는 부적절합니다. #### Cookie의 취약점 보완 쿠키는 클라이언트에서 `document.cookie`로 접근할 수 있기 때문에 XSS 공격으로 탈취될 수 있고, 중간에 도청을 했을 때도 탈취될 수 있습니다. 그래서 JS로 쿠키를 접근할 수 없게 `httpOnly: true`를 설정하고 도청을 방지하기 위해 서버간의 연결을 https로 사용하고 `secure: true` 을 설정합니다. #### 쿠키로 무엇을 할 수 있을까? 팝업창의 다시보지 않기 버튼의 체크유무를 파악할 수 있습니다. 또한, 장바구니 서비스에 이용할 수 있고 사용자마다 개인화 서비스를 제공하기 위한 입력 데이터로 사용됩니다. #### Session이란 무엇인가? 서버에서 사용자들을 식별하는 기법입니다. http가 무상태 프로토콜로 설계되어 사용자들을 각각 식별할 수 없었습니다. 그래서 쿠키를 id로써 사용해 서버에서 이를 인지하고 사용자를 인식합니다. #### Cookie와 Session의 차이 쿠키는 클라이언트의 메모리나 디스크에 저장되며, 노출 시 큰 피해가 가게됩니다. 또한, 영속 쿠키의 경우 브라우저를 종료해도 파일로 남게 됩니다. 하지만 세션은 서버에 저장된 데이터로, 데이터가 노출되어도 session id만이 노출됩니다. 또한, 브라우저가 종료되면 만료 시간에 상관없이 삭제됩니다. ### JWT #### JWT란 무엇인가? API 인증에 사용하는 토큰으로, Header와 Claim Set, Signature로 구성된 토큰입니다. Header는 토큰을 어떻게 해석할지에 대한 정보를 담고 있으며, 토큰 복호화 시, 이 부분을 먼저 해석합니다. 이 부분은 암호화한 것이 아니라 `base64`로 변환한 것입니다. Claim Set은 실제 데이터가 있는 부분으로 이 또한, 암호화한 것이 아니라 `base64`로 변환한 것입니다. Signature는 앞서 말한 것돠 다르게 인코딩된 것이 아닌 `header인코딩값.claimSet인코딩값`을 암호화된 데이터입니다. 이 데이터를 통해 서버는 올바른 클라이언트에게 받은 토큰인지 인지할 수 있습니다. #### JWT 장단점 session과 다르게 사용자를 식별하기 위해 저장소를 접근하는 것이 없어 서버 부하가 줄어듭니다. 또한 서버를 Clustering할 때 session을 사용하는 경우 공유 자원으로 사용하지 않으면 구현이 복잡해지지만 JWT 경우 서버가 아닌 클라이언트가 소유한 것이기 때문에 적절하게 사용할 수 있습니다. 하지만 실제 데이터가 암호화된 것이 아니기 때문에 잘못된 클라이언트를 인지할 수 있어도 데이터 도청을 막을 수 없습니다. 또한, Claim Set 내용이 많을수록 트래픽이 증가합니다. 또, 토큰을 강제로 만료시킬 방법이 없습니다. #### Refresh Token Access Token 단독 사용으로 생기는 보안 문제를 좀 더 나아지게 하기 위해 사용하는 토큰입니다. 탈취된 토큰을 하루 빨리 유효성을 없애기 위해 토큰 자체의 유효기간을 적게하기 위해 사용합니다. Refresh Token을 사용하지 않고 유효기간을 적게하면 사용자의 로그인 빈도 수가 많아지지만 Refresh 토큰의 유효성을 검사해 별도의 로그인 없이 Access Token을 새롭게 발급하게 해줍니다. ### Oauth이란? 제 3의 서비스를 사용하기 위해 인증과 권한을 관리하는 프로토콜입니다. Oauth 2.0은 반드시 HTTPS를 사용해야 하고 Access Token의 만료기간이 무조건 존재합니다. - fedorate identification - 하나의 서비스 계정만 관리하면 다른 서비스를 사용할 수 있다. #### Oauth 과정 Oauth 인증 방식은 4가지가 있지만 권한 코드 허락 방식만 알고 있습니다. 1. 먼저 Resource Owner가 Client에게 인증을 요청합니다. 2. 그럼 Client는 외부 서비스의 로그인 페이지를 응답하게 됩니다. - 이 때 client id와 scope, redirect_url을 query로 제공합니다. 3. 로그인 시, Resource Server는 해당 정보(scope, redirect_url)가 적절한지 판단 후 Resource Owner에게 동의를 구하는 페이지를 보여줍니다. 4. Resource Owner가 동의하게 되면 Authorization code를 url에 query에 포함시켜 Resource Owner에게 callbackURL로 Redirection 시킵니다. 5. Client는 Authorization code 뿐만 아니라 자신의 Client id와 Client Secret을 Authorization Server에게 전달합니다. 6. Authorization Server는 Authorization code를 지우고 accessToken을 Client에게 발급합니다. #### SNS Login와의 차이 일부 서비스의 경우 Resource Server 없이 Authorization Server만을 사용하는 차이가 있습니다. 하지만 크게 보면 SNS Login은 Oauth 프로토콜을 사용하는 하나의 서비스일뿐입니다. ### 웹 표준 #### 웹 표준이 무엇일까? 웹에서 사용되는 기술이나 규칙을 정한 것을 말합니다. #### 웹 표준을 왜 준수해야 하는가? 1. 웹 접근성이 향상되어 모든 사용자가 신체적, 환경적 조건에 관계없이 웹 서비스를 사용할 수 있게 보장하는 것입니다. 2. html, css, javascript를 역할에 맞게 분리해서 사이트를 작성해 CSS, JS 파일의 캐싱을 사용해 트래픽을 줄일 수 있습니다. 3. 구조와 표현을 분리하기 때문에 프로그래밍, 디자인 등이 동시에 진행될 수 있어 개발기간이 줄어들고 유지보수가 쉬워집니다. 4. meta 요소를 이용해 문서의 적절한 제목과 의미에 맞는 마크업으로 검색 결과에 영향을 줄 수 있게 됩니다. 5. 호환성의 확보를 통해 기존의 브라우저들이 동일한 사이트 화면을 보여주게 됩니다. ### 웹 표준을 지키려는 노력을 한 적이 있는가? #### 웹 접근성이 무엇인가? 모든 사용자들이 모든 기기에서 신체적, 환경적 결함이 있어도 편리하게 웹 서비스를 이용하는 것입니다. 이를 권고하는 법안으론 장애인 차별 금지법이 있으며, w3c의 WCAG 지침을 통해 권고받는 사항입니다. #### 웹 접근성을 향상 시키는 방법 ![](https://i.imgur.com/1CwcAi4.png) 시각 장애인들을 위해 텍스트가 아닌 콘텐츠에 IR기법을 사용합니다. img 경우 alt 속성을 사용할 수 있습니다. 하지만 이미지 썸네일 리스트인 경우 alt와 title 텍스트가 겹칠 수 있으므로, alt를 ""로 설정하고 텍스트를 `<a>`내에 `<img>`의 형제 요소로 넣습니다. 또한, QRCode같은 경우엔 찍을 경우 어떻게 되는지를 명확히 표시합니다. 또한, 색약과 색맹을 위해 고대비 효과나 차트나 슬라이드 버튼을 색깔뿐만 아닌 크기나 패턴을 적용해 구분시키는 방법이 있습니다. 또한, 스크린 리더나 키보드의 흐름이 사용자의 생각과 맞아 떨어지게 하기 위해 마크업을 논리적으로 배치시켜야 합니다. 또한, 정교한 조작을 못하는 상황을 위해 컨트롤 버튼의 대각선 길이를 최소 6mm로 정해야 되며, 버튼끼리 1px 이상의 여백이 있어야 합니다.