2020년 11월 10일 화요일

경력직 컴퓨터공학 지식

웹 개발 (프론트/백) 경력직 프로그래머 면접에 도움이 될 만한 내용으로 Index 형식 구성중. 

내가 무얼 모르는지 아는게 중요하다. 

신입 프로그래머 컴퓨터공학 지식: https://softwarepatrasche.blogspot.com/2016/04/blog-post.html?showComment=1606787920137#c9214959261385290037


Javascript
Javascript 동작원리
 - Javascript는 싱글스레드 : 하나의 메인 스레드와 하나의 콜스택을 가짐
 - 콜스택: LIFO 형식의 코드 수행 저장소
 - 메모리 힙: 메모리를 할당받는 곳
 - Javascript 런타임: JS엔진을 구동하는 환경. 브라우저 혹은 Node js
 - 즉, Javascript는 기본적으로 싱글스레드 이지만, 런타임 환경(브라우저 기준)이 제공하는 이벤트 루프, 태스크 큐, Web API의 조합으로 비동기 코드를 수행할 수 있음
 - 동작방식(브라우저 기준): 비동기 함수가 Web API에 위임됨 -> 수행된 함수는 이벤트 루프를 통해 태스트 큐에 저장됨 -> 콜스택에 어떠한 함수도 없을 경우 태스크 큐의 함수를 콜스택에 넘겨줌
Nodejs 동작원리 
 - Node.js 란: Javascript를 브라우저 밖에서도 사용할 수 있도록 하는 런타임
 - Node.js 작동방식: 싱글스레드, 이벤트 드리븐, Non-Blocking I/O 기반 JS 런타임
 - Node.js 내부구조 : Node.js Core, Node.js Bindings, V8 Engine, libuv
  + 이벤트 드리븐: 이벤트가 발생할 때 마다 미리 정해둔 작업(콜백함수)을 수행하는 방식
  + libuv 내에 위치한 이벤트 루프는 6개의 phase를 가지고 있으며, 계속 순회하며 비동기 호출을 처리한다.
  + Non-Blocking I/O : I/O 관련 블로킹 작업들을 백그라운드(OS, libuv 스레드풀 - 멀티스레드)에서 수행하고, 이를 비동기 콜백함수로 이벤트 루프에 전달하는것을 말함
프로세스와 쓰레드
 - 프로그램: 어떤 작업을 위해 실행할 수 있는 파일
 - 프로세스: 메모리에 올라와 실행되고있는 독립개체. 운영체제로 부터 자원을 할당받음.
  + 할당받는 자원: CPU time, 메모리 영역(Code, Data, Stack, Heap)
  + 별도의 주소공간에서 수행. 다른 프로세스의 변수나 자료구조에 접근 불가능
  + 접근하려면 프로세스간 통신(IPC)을 해야함: 파이프, 소켓, 파일 등.. 
 - 스레드: 프로세스 내에서 수행되는 흐름단위, 특정한 수행경로, 할당받은 자원을 이용하는 실행단위.
  + 프로세스 내에서 Stack만 따로 할당받고 다른 자원은 모두 다른 스레드와 공유한다.
 - 멀티프로세스: 하나의 프로그램을 여러 프로세스로 구성하여 각 태스크를 수행하도록 하는 방식. 장점: 하나의 프로세스가 문제가 발생하도 전파되지 않는다 / 단점: Context Switching 오버헤드(캐시 메모리 초기화), 복잡한 IPC 기법
 - 멀티스레드: 하나의 프로그램을 여러 스레드로 처리하는 기법. 장점: 소모자원 감소, 간단한 통신 / 단점: 주의깊은 설계, 까다로운 디버깅, 한 스레드의 문제가 확산, 동기화문제
Javascript Advanced
 - ES5 & ES6 차이점: https://yngmanie.space/posts/es5_vs_es6
 - 탬플릿 리터럴, 해체할당, Promise, async/await 등
Javascript 문법
 - 호이스팅, 비구조화, 모듈, 객체/배열 리터럴: https://frontcode.tistory.com/50?category=685416
  + 호이스팅: 함수안에 있는 선언들을 모두 끌어올려서 해당 유효범위의 최상단에 선언하는 것
 - Prototype 상속 ES5 스타일: https://evan-moon.github.io/2019/10/27/inheritance-with-prototype/
 - This와 class: https://ssungkang.tistory.com/entry/ES6-Class의-상속-super-this
 - This와 bind: https://kamang-it.tistory.com/entry/JavaScript07this-this바인드편bindcallapply
 - This 주의할 점: https://kamang-it.tistory.com/entry/JavaScript-08this-세세한-이야기편?category=765562
 - 클로저: 선언 당시의 상태(환경)를 기억하고 있는 것/ 함수 내부의 함수: https://hyunseob.github.io/2016/08/30/javascript-closure/

Test
Javascript 유닛 Test Code
desccribe('test function', () => {
    it('test sum', () => {
        expect(sum(1,5)).toBe(6);
    })
})
TDD(Test Driven Development): 테스트 코드를 먼저 작성한 후 기능을 작성하는 방법론

Database
DBCP(Database Connection Pool)
 - 다수의 Http 요청에 대해 매번 DB에 connection을 만들지 않고, Connection Pool을 이용해 connection 생성 부분에 대한 비용과 대기시간을 줄임
 - WAS가 실행되며 미리 일정량의 DB connection 객체를 생성 및 저장
 - 요청에 따라 Pool에서 객체를 가져다 쓰고 반환
 - WAS Thread 수 >= DB connection pool 수 로 설정하는것이 바람직, 수가 많을수록 memory 많이 차지
 - Spring 시스템에서 Stateless 기반에서 Stateful로 변경할 때 JDBC설정을 어떻게 바꾸어야 하는가?

Web
WSGI(Web Server Gateway Interface)
 - CGI(Common Gateway Interface)의 일종. CGI란? 웹 서버와 외부 프로그램 사이에서 정보를 주고받는 방법이나 규약
 - WSGI랑? Web 서버가 받은 호출을 Python 어플리케이션에게 전달하고 응답받기위한 호출조약
 - WSGI module(Werkzeug), WSGI process(gunicorn)


Docker
docker
docker-compose
kubernetes

Security
TLS,SSL
Public/Private key

REST API

MSA (Micro Service Architecture)
- Ambassador pattern : 기존 Application이 외부 서비스와 통신할 때 프록시 서버를 중간에 추가하여 Routing, Monitoring, Security, Logging 의 기능을 부여하는 것. 기존 Application들이 다양한 언어로 구성되어 있고, Lagacy로써, 쉽게 고치거나 하기 어려울때 유용. 기존 Application 과 동일 인스턴스에 배포하여 구성할 수 있다.
 - Anti-Corruption Layer pattern : Lagacy에서 New system으로 점진적 이동을 할 경우, 두 시스템간의 communication을 유지야 할때 사용. 그렇지 않으면 필수적으로 New System이 Lagacy를 호환해야 하며 그로인한 Corruption이 발생된다. 또한 semantic이 다른 두 서브 시스템간의 커뮤니테니션 목적으로도 사용
 - Asynchronous Request-Reply pattern : 클라이언트-서버 사이드 간 비동기 요청을 처리하는 방식. Long-running api 이거나 Callback endpoint를 제공할 수 없는경우 사용. 클라이언트에서 API endpoint로 요청을 보냄 -> 서버는 즉시 202를 리턴 with status endpoint -> 클라이언트는 일정시간 후 status endpoint로 요청을 보냄 -> 서버는 api가 수행될때까지 지속적으로 202를 리턴 -> 서버측에서 요청이 수행되면 302로 응답 with resource uri-> 클라이언트는 resource uri에 접근 -> 200 return
 - Backends for Frontends : 처음에는 Web UI를 대응하기 위한 Backend를 구축했지만, App 대응을 위해서 동일한 백앤드를 사용하는 경우, 다양한 이유로 Conflicting update requirements 를 마주치게 될 수 있다. 백엔드가 Bottleneck이 되지 않기 위해, 각 Frontend별로 Backend를 따로 구성하여 해결한다.
 - Bulkhead : Consumer가 Service에게 요청을 보낼 때, 적절치 못한 request로 해당 Service가 Exhausted되는 경우가 있음. 이럴 경우, 다른 Consumer들의 request들이 해당 Service에게 요청을 보내는 경우 응답을 받지 못함으로 Connection pool을 잡고 놔주지 않는 경우가 발생. 결국 모든 Connection pool은 소진되고, 해당 Service 뿐만 아니라 다른 Service들의 요청 또한 Connection pool 부족 문제로 실패하게 됨. 이럴경우, Service별로 connection pool을 배분(partition)하여 해결한다. 혹은 각 Client별로 Service instance를 개별적으로 할당하는 방법도 존재.
 - Cache-Aside : 캐시 서버가 read-through, write-through 기능은 자체적으로 제공하지 않을 때, 해당 캐시가 storage와 consistency를 유지할 수 있도록 하는 방안. application이 storage 원본 데이터를 변형했을 때, 캐시서버의 해당 데이터에 대해 invalid 처리를 한다. 그럼 다음 application이 해당 데이터를 캐시에서 읽이려 할 때 원본 데이터로 업데이트 할 것.
 - Choreography: 여러 서비스를 linear하게 이용해야 하는 operation의 경우 보통 중앙에 orchestrator가 해당 잡을 맡게되지만, 이렇게 할 경우 관리가 어렵고 각 서비스에 디펜던시가 생기게 되어 서비스들의 내용 변경 시 orchestrator 또한 수정해야 한다. 이를 극복하기 위해, 중앙에 orchestrator 대신 Meesage Queue를 두어 각 서비스가 request를 보내고, 다음 서비스를 호출하는 식의 linear한 job을 중앙 디펜던시 없이 이룰 수 있도록 함.
 - Circuit Breaker: application이 서비스를 호출할 때 해당 operation이 지속적으로 실패한다면, retry pattern을 통해 재요청을 할 것 이며, cpu/memory/thread를 점유할 것. 문제가 해결되지 않는다면 전체 시스템에 중대한 문제를 야기할 것 임으로, 적절하게 끊어줄 필요가 있음. Circuit Breaker는 해당 서비스 앞에 Proxy서버로 붙어서 Closed/Half-Open/Open 세 가지 상태를 순회하며 요청이 오는 request를 operation에 넘겨줄 것 인지 아닌지 판단. 서비스가 요청을 받을 수 있다면 Closed, 상황을 봐야한다면 Half-Open, 받을 수 없는 상태라면 Open.


Algorithm
C++ 문법
 - 표준자원: 시간(1초), 메모리(heap + static: 256MB, stack: 1MB)
  + 전역, Static 변수: static 영역 저장
  + 동적할당: Heap 영역 저장
  + 지역변수, 매개변수: Stack 영역에 저장 (함수 수행완료 이후 사라짐)
  + 수행시간 어림짐작: 1초당 1억회
 - 동적할당: heap 영역에 저장되는 변수
  + Memory leakage: stack과 달리 heap영역의 변수는 사용 후 해제해 주어야 한다. 프로그램 종료시 까지 메모리가 낭비된다.
  + 1차 배열 동적할당
    int* p = new int[n]
    delete p
  + 2차 배열 동적할당
    #include <string.h>
    int **arr = new int*[sizeY]
    for(int i=0; i < sizeY; ++i ) {
        arr[i] = new int[sizeX};
        memset(arr[i], 0, sizeof(int)*sizeX);
    }
    for(int i=0; i < sizeY; ++i) {
        delete [] arr[i]
    }
    delete [] arr;
 - 매개변수
    2차원 정적배열 매개변수: 최종 dimension 크기 지정 필요
        void function(int arr[][sizeX]) { }
    2차원 동적배열 매개변수: 크기 지정 필요 X
        void function(int **arr) { }
 - 형식별 바이트 수
    bool/char: 1byte(4bit), Int/unsigned int: 4byte(32bit), double/long long: 8byte(64bit)
    int: -2,147,483,648(-2^31) to 2,147,483,647(2^31)
    unsigned int: 0 to 4,294,967,295(2^32)

 - 비트연산: signed 정수에서 적용방식을 보장하지 않음으로 unsigned 정수 자료형을 사용해야 함
    << / >> : 왼쪽, 오른쪽으로 이동. 끝자리는 소실
    & / | / ^ : AND, OR, XOR
    할당 연산: x<<y / x>>y / x &= y / x |= y / x ^= y
 

실제 경력직 면접 질문
Q. Nodejs는 싱글 쓰레드 framework 인데 어떻게 비동기처리가 가능한가?
Q. MSA에 대해 설명해봐라
Q. Sidecar 패턴에 대해 설명해봐라
Q. Stateful과 Stateless 특징에 대해 설명해봐라
Q. Spring으로 구성된 서비스에서 Stateless -> Stateful 로 넘어가려면 어떤걸 바꾸어야 할까
Q. 두 배열을 숫자로 변환하여 합친 후 다시 배열로 만들기
Q. 알파벳 배열에서 중복되지 않은 가장 큰 substring 구하기
Q. Linked List를 한 숫자 기준으로 좌 우로 정렬하기

    
    

댓글 없음:

댓글 쓰기