반응형

자바스크립트는 싱글 쓰레드이지만, 크롬 브라우저의 탭 하나하나는 각각 하나의 프로세스이고 멀티 쓰레드 환경이다. 

이전에 썼던 이벤트 루프 관련 글에서 정확히 브라우저의 내부 구조가 어떻게 구성되었는지 궁금해서 찾아보았다. 

 

참고) 이전글

https://lodado.tistory.com/16

 

[이벤트루프] 자바스크립트에서 정확한 타이머 구현?

*잘못된 부분이 있으면 피드백 주시면 감사하겠습니다! 자바스크립트에서 타이머 이벤트를 쓸 수 있는 방법으로는 setTimeout, setInterval 두가지가 있다. 이 함수들이 어떻게 비동기를 지원할까? 자

lodado.tistory.com

컴퓨터 아키텍처 3개 레이어 - 브라우저가 돌아가는 환경

 

하단부의 Machine Hardware, 중앙부의 운영 체제, 상단부의 어플리케이션.

 

브라우저가 돌아가는 환경을 이해하기 위해서는 컴퓨터의 전반적인 구조를 이해할 필요가 있다.

 

Machine Hardware (스마트폰, 컴퓨터 등)

 

물리적으로 구현된 하드웨어 위에서 컴퓨터가 동작

실제 작업을 물리적으로 처리하는 공간이다.

최근에는 브라우저에서 단순 CPU를 넘어서서 고속 렌더링, 에니메이션을 처리하기 위해 추가적으로 GPU라는 개념이 등장했다.

 

CPU 

Central Processing Unit - CPU

 

CPU는 컴퓨터의 뇌라고 볼 수 있다.

다양한 작업을 실제적으로 처리하는 공간이다.

최근엔 싱글 CPU를 넘어서서 멀티 코어등 다양한 방식을 이용해 '병렬성'을 지원하려는 연구가 활발하다.

 

GPU

 

Graphics Processing Unit - GPU

최근 브라우저에서 GPU를 이용하려는 연구도 활발하다.

GPU는 공장이라고 비유할 수 있다.

CPU는 다양한 작업을 유연하게 처리하는데 특화되어 있다면

GPU는 연산을 수많은 코어에서 동시에 처리하는데 특화되어 있다.

GPU 가속 연산 덕분에 CPU 하나로는 오래 걸릴 연산을 금방 끝낼 수 있다.

 

GPU가 연산을 하기 위해서는 CPU가 GPU에 데이터를 전송해줘야 연산이 가능하다.

이것을 비유하자면 CPU는 배송 트럭이라고 생각하고, GPU는 공장이라고 비유해보면 좋을것 같다.

 

GPU Bottleneck - 병목현상

CPU가 배송(I/O, 효율적인 프로그래밍)를 빨리 해줘야 공장이 100% 효율로 가동 가능하다.

공장이 최신식(GPU의 성능이 매우 좋아도)이라도 CPU의 배송이 느리다면 제 효율을 낼 수 없다.

그리고 반대로 배송(CPU의 성능이 매우 좋아도)이 엄청 빨라도 공장의 효율이 좋지 않다면 제 효율을 낼 수 없다.

 

요약하자면 둘 다 중요하다.

안드로이드 같은 경우 웹앱을 사용할 경우

GPU 연산이 좋다고 모든 연산을 위임하다보면 위 GPU Bottleneck 현상 혹은 너무 많은 작업으로 오히려 CPU만 사용할때보다 느려질 수 있다.

 

그리고 하드웨어적인 한계가 있기 때문에 CPU, GPU의 성능을 아무리 올려도 언젠간 한계에 부딫치게 된다.

프론트엔드 엔지니어가 관여할 수 있는 부분은 '렌더링 최적화' 등 주어진 자원 내에 최대의 효율을 내는게 주 업무다.

 

Operating System (윈도우, 리눅스, 안드로이드 등)

 

소프트웨어적으로 구현된 운영체제 위에서 어플리케이션이 동작 

(운영체제는 하드웨어와 이용자 사이에서 쉽게 이용할 수 있도록 인터페이스 역할을 한다. 윈도우가 왜 이름이 '윈도우'인지 생각해보면 좋을듯!)

 

Application (브라우저 - 크롬, 오페라 등)

 

우리가 사용하는 브라우저 어플리케이션이다. 운영체제가 지시하는 메커니즘에 따라 CPU & GPU를 동작 시키게 요청한다. 

동작(프로그래밍)을 잘 시키냐에 따라 브라우저의 제 성능을 이끌어낼 수 있다. 

 

프로세스 & 쓰레드

 

그리고 브라우저 아키텍처를 이해하기 이전에 프로세스 & 쓰레드 구조를 이해할 필요가 있다. 

이 부분은 면접 단골질문이기도 하고 학교에서 많이 배우므로 간략하게 설명하고 넘어가겠다.

 

프로세스 

 

프로세스는 운영체제로부터 자원을 할당받은 작업의 단위이다.

즉, 어플리케이션 하나가 프로세스 하나가 될 수 있다.

 

참고) 프로그램에 대해

 

더보기

프로그램은 어떤 작업을 위해 실행 할 수 있는 파일을 말하며 메모리구조에서 code 영역에 있는 실제 물리적 파일을 뜻한다.

프로세스는 컴퓨터에서 연속적으로 실행되고 있는 컴퓨터 프로그램을 뜻하며 메모리에 올라와 실행되고 있는 프로그램의 인스턴스이다.

 

즉, 프로그램(passive) <-> 프로세스(active)관계라고 할 수 있다.

 

쓰레드 

 

쓰레드는 프로세스 내에서 운영체제로부터 할당받는 자원을 실행하는 단위이다.

프로세스 내부에서 여러개가 생길 수 있다.

 

그외 자세한 정보는 다음 링크 추천 

https://gmlwjd9405.github.io/2018/09/14/process-vs-thread.html

 

[OS] 프로세스와 스레드의 차이 - Heee's Development Blog

Step by step goes a long way.

gmlwjd9405.github.io

 

프로세스와 쓰레드 생성 과정

 

process 내부의 쓰레드들

 

어플리케이션이 실행되면 프로세스가 생성되고,

프로세스는 작업을 위해 쓰레드(들)을 생성 할 수 있다.

그리고 OS는 프로세스에게 메모리 한 조각을 주고 모든 상태 정보를 고유 메모리 공간에 저장할 수 있게 한다. 어플리케이션이 끝나면 프로세스도 사라지고 OS가 메모리를 해제한다.

 

(개인적 생각으로 여기서 말하는 메모리는 RAM 메모리를 뜻하는것으로 추론된다.)

프로세스간 통신 - Inter Process Communication (IPC)

 

IPC

그리고 프로세스는 다른 프로세스에게 별도의 작업을 수행하도록 요청 혹은 통신이 가능하다. 많은 어플리케이션이 이 방식을 채택하고 있어 워커 프로세스가 무응답 상태에 빠지더라도 어플리케이션의 다른 부분을 수행하고 있는 프로세스들을 종료할 필요 없이 해당 프로세스만 재시작할 수 있다.

 

IPC에 대한 정보는 다음 링크 추천

https://jwprogramming.tistory.com/54

 

IPC의 종류와 특징

IPC(Inter Process Communication) - 프로세스 간 통신에 대하여 종류와 특징들에 대하여 살펴보겠습니다. [리눅스 커널 구조] - 위 그림처럼 Process는 완전히 독립된 실행객체입니다. 서로 독립되어 있다

jwprogramming.tistory.com

 

브라우저 아키텍처

 

다른 여러 브라우저 구조들

중요한점은 브라우저를 구현하는 '표준'이 없기 때문에 브라우저(IE, 오페라, 웨일, 크롬 등등..)마다 내부 작동 방식이 다를 수 있다.

 

그래서 공통적인 흐름을 이해하는것이 중요하다. (ex : 프로세스 & 쓰레드 구조로 동작하는구나!)

이 글은 2018년 기준 크롬 브라우저를 기준으로 설명한다.

 

크롬의 멀티 프로세스 아키텍처 도식도

 

크롬은 멀티 프로세스 아키텍처를 이용한다.

*중요점 : 크롬은 여러개의 렌더러 프로세스를 가질 수 있다(보통 탭 하나당 하나).

 

각 중요한 프로세스의 설명은 다음과 같다.

프로세스 설명
브라우저 주소 창, 뒤로 및 앞으로 이동 버튼을 포함한 어플리케이션의 "chrome" 부분을 제어합니다.
또한 네트워크 요청 및 파일 액세스와 같은 웹 브라우저의 권한이 부여된 보이지 않는 부분을 제어합니다.
렌더러 웹사이트가 디스플레이 될 때 탭 안의 모든 것 담당.
플러그인 플래시와 같은 웹사이트가 사용하는 모든 플러그인 담당.
GPU 다른 프로세스와 분리된 GPU 작업을 제어합니다. GPU는 여러 앱의 요청을 제어하고 동일한 표면에 표시하기 때문에 다른 프로세스로 분리됩니다.

 

멀티 프로세스 아키텍처의 장점

 

그럼 왜 이런 멀티 프로세스 구조를 가질까?

 

개별 탭에서 실행되는 여러 프로세스의 도식도;

 

보통 탭 하나당 하나의 프로세스를 가진다. 

(추가적으로 사이트 격리 옵션이 켜지고 iframe이 내부에서 실행되면 하나의 개별 Renderer 프로세스를 또 가진다)

 

참고)

https://blog.chromium.org/2017/05/improving-extension-security-with-out.html

 

Improving extension security with out-of-process iframes

Security is critical to Chrome, and many features protect Chrome users as they browse the web. Google Safe Browsing warns users away from ...

blog.chromium.org

 

만약 크롬이 단일 프로세스 환경이고 renderer process가 다중 쓰레드 환경이라면 한 탭이 고장이 나게 되면 모든 탭에 영향을 끼치게 된다. (메모리 영역에서 stack을 제외한 heap, code, data 등 여러 영역을 공유하기 때문?) 

 

그런데 다중 프로세스 환경이라면 탭이 하나 고장한 경우 그냥 닫아버리고 다른 탭으로 이동하면 된다.

 

그외 장점으로는 보안 및 샌드박싱 (운영체제는 프로세스의 권한을 제한하는 기능을 제공)이 있다.

 

메모리 공간 절약

 

최종적인 크롬의 아키텍처

그런데 각 프로세스가 메모리 공간을 할당받아 사용하다보면 메모리 부족 현상이 일어날수도 있고 효율적이지 않다.

그래서 크롬이 고성능 장치에서 실행될 때에는 안정성을 위해 각 서비스를 별개의 프로세스로 분리하고, 자원이 부족한 장치에서는 서비스를 하나의 프로세스로 합쳐 메모리 점유를 낮추는 메커니즘이 들어가 있다.

 

즉, 크롬에서 최대 프로세스 개수에 제한을 두었다.

이 구조는 안드로이드에서도 구현되어 있어 유사한 프로세스를 합쳐 메모리 점유를 줄이는 방식을 실행한다.

 

기타 브라우저의 동작 방식

 

전반적으로 mutli process architecture를 따르는 듯하다.

 

IE8

 

 

 

크롬의 브라우징 프로세스와 렌더링 프로세스 두개를 심플하게 가지는거 같다.

One mainframe process

Zero or multiple tab processes

tab process의 경우 RAM 크기에 따라 자동으로 크기가 조절된다.

 

Firefox

 

Firefox의 경우엔 멀티 프로세스 아키텍처인것은 크롬과 동일하다. 다만 4개까지의 다중 프로세스를 허용하고 이후 

탭의 경우는 구글과 비슷하게 기존 프로세스 내부에서 메모리 영역을 공유한다.

 

Chrome using 1.77x more RAM than Firefox in 64-bit and 2.44x in 32-bit mode. (모질라의 주장에 따르면!)

 

모질라의 주장에 따르면 자기들이 메모리를 제일 적게 쓴다고 하는데

프로세스를 4개까지만 만드니까 당연한 내용이다 😂

 

 

같이 읽어보면 좋을 글)

https://levelup.gitconnected.com/how-web-browsers-use-processes-and-threads-9f8f8fa23371

 

How web browsers use Processes and Threads

A process can be described as an application’s executing program. A thread is the one that lives inside of process and executes any part…

levelup.gitconnected.com

 

https://medium.com/@cwdoh/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC-%EC%9C%84%ED%95%9C-%ED%81%AC%EB%A1%AC-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%84%B1%EB%8A%A5-%EC%9D%B8%EC%9E%90-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-4c9e4d715638

 

프론트엔드 개발자를 위한 크롬 렌더링 성능 인자 이해하기

3년 전에 개인 블로그에 적었던 글이라 이미 보신 분들도 있으리라 생각됩니다만, 미디엄에서 이전의 기술관련 글들을 같이 관리할 겸 같이 포스팅하기로 하였습니다. :)

medium.com

 

reference 

 

https://wvganjana.medium.com/how-web-browsers-use-process-threads-67e156abb3c5

 

How web browsers use Process & Threads

As we all know Chrome and Firefox both using multi-threading in architecture. But they support it in different ways.

wvganjana.medium.com

 

https://www.wepc.com/tips/cpu-gpu-bottleneck/

 

CPU and GPU Bottleneck: A Detailed Explanation

Have you ever experienced playing a game and you get sudden FPS drop from time to time? The next second, you’re dead.. If you try to observe, these sudden

www.wepc.com

 

https://developers.google.com/web/updates/2018/09/inside-browser-part1?hl=ko 

 

모던 웹 브라우저 들여다보기 (파트 1)  |  Web  |  Google Developers

브라우저에서 사용자 코드를 하이레벨 아키텍처부터 렌더링 파이프라인 세부 기능에 이르는 기능성 웹사이트로 전환하는 방법

developers.google.com

 

반응형
반응형

 

*잘못된 부분이 있으면 피드백 주시면 빠르게 수정하겠습니다!

 

ES5까지는 변수를 선언하는 방법은 var 밖에 없었습니다.

다만 변수의 유효범위를 설정하는데 어려움을 겪어서 ES6 이후 지역변수를 다루기 위해서 let, const가 등장하게 됩니다.

(var는 추가적으로 블록 스코프가 아닌 '함수 스코프' 개념을 따릅니다.)

자세한건 아래 링크를 참고하세요.

 

https://poiemaweb.com/js-scope

 

Scope | PoiemaWeb

스코프는 참조 대상 식별자(identifier, 변수, 함수의 이름과 같이 어떤 대상을 다른 대상과 식별할 수 있는 유일한 이름)를 찾아내기 위한 규칙으로 자바스크립트는 이 규칙대로 식별자를 찾는다.

poiemaweb.com

 

 

호이스팅

 

JavaScript에서 코드를 실행하기 전 평가실행 과정을 거칩니다.​

그리고 변수는 위의 사진처럼 선언, 초기화, 할당이라는 3가지 단계를 거쳐 생성됩니다.

 

선언 단계(Declaration phase) : 변수를 실행 컨텍스트의 변수 객체에 등록하는 단계를 의미합니다. 이 변수 객체는 스코프가 참조하는 대상이 됩니다.

초기화 단계(Initialization phase) : 실행 컨텍스트에 존재 하는 변수 객체에 선언 단계의 변수를 위한 메모리를 만드는 단계 입니다. 이 단계에서 할당된 메모리에는 undefined로 초기화 됩니다.

할당 단계(Assignment phase) : 사용자가 undefined로 초기화된 메모리의 다른 값을 할당하는 단계 입니다.

모든 변수는 생성되면 위 3단계를 거쳐 생성됩니다.

그래서 자바스크립트가 실행되면 모든 변수들은 평가단계를 거치게 되는데, 호이스팅이란 모든 변수들을 끌어 모아서 각 유효범위(블록 {}안)에 최상단에 선언하는것을 말합니다.

var, let, const 모두 위 3단계를 거칩니다.

다만 var는 선언단계와 초기화 단계가 호이스팅 단계에서 동시에 실행됩니다.

그래서 아직 할당이 되지 않았는데 var로 생성된 변수를 부르게 되면 undefined를 되돌려 줍니다.

let,const는 선언은 되지만 초기화는 되지 않고, 할당이 되기 전까지 TDN(temporal dead zone)이라는 곳에 등록됩니다. 그래서 할당이 되지 않았는데 불러온다면 TDN 구간에 있는 변수들은 참조 에러(Reference Error)를 발생시키게 됩니다.

즉, 호이스팅은 모두 발생하지만 var와 let,const는 다루는 방법에 차이가 있게 되는것입니다.

다른 언어에서 흔히 쓰는 변수들은 구조적으로는 약간씩 다르겠지만 결론적으로 let, const와 동일하게 쓰인다고 이해하시면 편합니다.

참고로 함수 선언문은 위 3가지가 동시에 진행됩니다.

함수 선언식 예시

 

function func { ... }

 

그래서 어디서 선언하든 유효 범위 (스코프) 내에서는 사용할 수 있습니다.

함수 표현식 예시

함수 표현식은 변수처럼 동작하고 호이스팅 됩니다.

const func = () => { ... }
 

따라서 var, const, let중 뭘 썼는지에 따라 호이스팅되고 변수처럼 처리됩니다.

호이스팅을 하는 이유는 현재의 실행 컨텍스트의 지금 스코프 내부에 어떤 식별자들이 있는지 탐색하고, 렉시컬 환경에 저장(기록) 해놓기 위해서 입니다.

 

즉.. 자바스크립트의 모든 핵심 개념이 서로 연동되있다고 볼 수 있을꺼 같은데요

자세히 알아보시려면 JavaScript deep dive란 책을 읽어보시길 추천 드립니다!

 

 

그리고 이거에 대해서 재밌는 문제가 하나 있는데요,

클로저 개념과 연동되는 문제이니 한번 생각해 보시면 좋습니다.

 

for(var i =0; i <100; i+=1){
    setTimeout(function(){
        console.log(i);
    },i*1000);
}

해당 코드를 실행시키면 0, 1, 2, 3, 4가 출력되는게 아니라 100, 100, 100... 이 출력되게 되는데

원래 의도대로 고치려면 어떻게 해야할까요?

 

 

더보기
for(let i =0; i <100; i+=1){
    setTimeout(function(){
        console.log(i);
    },i*1000);
}

 

해설은 다음 글을 참고하세요.

 

https://www.bangseongbeom.com/javascript-var-let.html

 

자바스크립트 var, let 차이점

자바스크립트에서 변수를 선언할 때 사용하는 var, let, const의 차이와 스코프, 호이스팅에 대해 알아봅시다.

www.bangseongbeom.com

 

 

 

반응형
반응형

reflow, repaint를 피하거나 최소화

1. transition(CSS option)

성능 개선? 주제에 맞는 내용은 아니지만 부드러운 애니메이션을 구현하고 싶을때 참고

transform 속성은 reflow, repaint가 일어나지 않고 composite만 발생

(transform, opacity, cursor, orphans, perspective등도 Reflow, Repaint를 건너 뛴다,

원리는 브라우저에서 GPU를 사용해 하드웨어 가속하는 Update Layer Tree라는 내용 참고)

 

https://kyu9341.github.io/WEB/2021/02/03/WEB_GPU/

 

WEB - 하드웨어 가속 - kwon | kwon's Blog

하드웨어 가속 특정 작업을 CPU가 아닌 다른 특별한 장치를 통해 수행 속도를 높이는 것을 ‘하드웨어 가속(hardware accelerated)’이라 한다. 그래픽이나 사운드와 관련된 작업에 하드웨어 가속을 많

kyu9341.github.io

 

transition은 CSS 프로퍼티의 값이 변화할때 즉시 변화하는게 아니라

부드럽게 일정 시간에 걸쳐 일어나게 해준다

 

아래 예시 그림을 보자.

 

코드

<head>
  <style>
    .test-div {
      width: 100px;
      height: 100px;
      background: red;
    }
    .test-div:hover {
      border-radius: 50%;
      background: blue;
    }
  </style>
</head>

<body>
  <div class="test-div"></div>
</body>

 

네모에 마우스를 올리면 즉시 동그라미로 바뀐다.

그럼 transition 옵션을 부여한다면?

 

코드

<head>
  <style>
    .test-div2 {
      width: 100px;
      height: 100px;
      background: red;
      /* 트랜지션 효과: 모든 프로퍼티의 변화를 2초에 걸쳐 전환한다. */
      transition: all 2s;
    }
    .test-div2:hover {
      border-radius: 50%;
      background: blue;
    }
  </style>
</head>
<body>
  <div class="test-div2"></div>
</body>

transition은 자동으로 발동되지 않는다. :hover와 같은 가상 클래스 선택자(Pseudo-Classes) 또는 JavaScript의 부수적인 액션에 의해 발동한다. 

2. 클래스 변화에 따른 스타일 변화를 원할 경우, 최대한 DOM 구조 상 끝단에 위치한 노드에 추가

(부모가 바뀌면 자식에게도 영향을 준다?)

3. 애니메이션이 들어간 엘리먼트는 가급적 position: fixed 또는 position: absolute로 지정

애니메이션이 들어간 요소에 position: absolute 혹은 position: fixed 속성을 적용하면 다른 요소에는 영향을 끼치지 않으므로 페이지 전체가 아닌 해당 요소만 reflow가 발생

 

3. JS를 통해 스타일변화를 주어야 할 경우, 가급적 한번에 처리

var div = document.getElementsByTagName('div');
for (var i = 0; i < div.length; i++) {
    div[i].style.height = '80px';
    div[i].style.backgroundColor = '#00f';
    div[i].style.display = 'inline-block';
    div[i].style.overflow = 'hidden';
    div[i].style.fontSize = '40px';
    div[i].style.color = '#fff';
}

한번 style을 바꿀때마다 dom 조작이 일어나고 reflow-repaint가 일어난다.

즉, 순차적으로 dom 조작이 발생하는 식이다.

 

바꾸고 싶은 스타일을 담은 css class를 하나 만드는 식으로 구현하고, tag에 class를 붙이는 식으로 구현하자.

toggle이나 classList.add, classList.remove 등을 사용해서 js에서 class를 떼고 붙일 수 있다.

 

classList에 대한 내용)

https://hyunjungchoi.tistory.com/70

 

자바스크립트 classList를 써야하는 이유

~잠깐 사담~ 아직 공부한 지 얼마 안 됐지만, 자바스크립트는 너무 어렵다.ㅠㅠ 파이썬, 자바를 처음 배울때 보다 훨씬 어려움....ㅠㅠㅠㅠ 게다가 지금 챌린지 중인데, 잘하시는 분들 너무 많아

hyunjungchoi.tistory.com

 

혹은 cssText를 이용한다.

// Modal.jsuseEffect(() => {
    document.body.style.cssText = `position: fixed; top: -${window.scrollY}px`
  return () => {
    const scrollY = document.body.style.top
    document.body.style.cssText = `position: ""; top: "";`
    window.scrollTo(0, parseInt(scrollY || '0') * -1)
  }
}, [])

 

4. 인라인 스타일을 최대한 배제

3번 내용과 중복, reflow 비용을 줄이는 것 이외에 코드 가독성도 높일 수 있다.

 

5. 테이블 레이아웃을 피하는 것이 좋다.

테이블 값에 따라 넓이를 계산 -> 렌더링이 느려진다

만약 사용한다면 CSS 속성 table-layout:fixed를 사용하면 랜더링을 조금 더 빠르게 할 수 있다.

 

6. CSS 하위선택자는 필요한 만큼 정리

/* 잘못된 예 */
.reflow_box .reflow_list li .btn{
    display:block;
}
/* 올바른 예 */
.reflow_list .btn {
  display:block;
}

불필요한 선택자는 성능 저하

 

7. will-change 사용

 

미리 변화가 예상되는 요소를 브라우저에게 알려주는 기능이라는데 실제로 써보진 않았다.

불필요한곳에 남용하면 오히려 성능 저하를 일으킬 수 있는 요소

 

8. transform: translateY()등 이용

이동 애니메이션시 left, right 보다는 transform 이용(GPU 가속)

 

 

reference

 

https://poiemaweb.com/css3-transition

 

CSS3 Transition | PoiemaWeb

트랜지션(transition)은 CSS 프로퍼티 변경에 따른 표시의 변화를 부드럽게 하기 위해 애니메이션 속도를 조절한다. 즉, 프로퍼티 변경이 표시의 변화에 즉시 영향을 미치게 하는 대신 그 프로퍼티

poiemaweb.com

 

https://wit.nts-corp.com/2017/06/05/4571

 

CSS 애니메이션 성능 개선 방법(reflow 최소화, will-change 사용) | WIT블로그

CSS 애니메이션 성능 개선 방법(reflow 최소화, will-change 사용)

wit.nts-corp.com

 

https://medium.com/@bestseob93/%ED%9A%A8%EC%9C%A8%EC%A0%81%EC%9D%B8-%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%AA%A8%EB%8B%AC-react-modal-%EB%A7%8C%EB%93%A4%EA%B8%B0-bd003458e9d

 

효율적인 리액트 모달(react-modal) 만들기

안녕하세요.

medium.com

 

반응형

'Front-end > CSS' 카테고리의 다른 글

font-family 상속 시키기  (0) 2022.11.04
css 챌린지  (0) 2022.10.05
[CSS] box-sizing  (0) 2022.07.11
[CSS] Gap  (0) 2022.06.13
loading spinner  (2) 2022.02.13
반응형

*잘못된 부분이 있으면 피드백 주시면 감사하겠습니다!

 

자바스크립트에서 타이머 이벤트를 쓸 수 있는 방법으로는 setTimeout, setInterval 두가지가 있다.

 

이 함수들이 어떻게 비동기를 지원할까?

 

자바스크립트는 단일 쓰레드 기반의 언어이지만 이벤트 루프를 사용해서 동시성을 지원할 수 있다.

타이머를 실행시키면 Web API에서 타이머의 기한이 끝날때까지 대기하다가 테스크 큐로 들어오게 된다.

콜스택이 비었다면 테스크 큐에서 테스크를 가져와 실행한다.

 

이 말이 무엇인가를 다시 풀어써보기로 하자.

우선 Web API가 뭔지부터 알아야 할것 같다.

Web API 와 Javascript 런타임 

런타임이란 해당 프로그램 언어가 작성된 코드가 구동되는 환경을 뜻하고, 웹 브라우저나 Node.js 가 대표적 JS 런타임이다. 그리고 JS 이외에 다양한 기능을 제공하기 위해서 브라우저에서는 웹 API가 여러 함수(setTimeout등)을 지원하고, Node에서는 화면의 예시처럼 fs 등 함수를 지원하게 된다. 

 

브라우저 환경 구조 

자바스크립트 엔진

 

- Heap : 객체들은 힙 메모리에 할당된다. 크기가 동적으로 변하는 값들의 참조 값을 갖고 있다.
- Call Stack : 함수 호출 시, 실행 컨텍스트가 생성되며, 이러한 실행 컨텍스트들이 콜 스택을 구성한다.

 

Web API or Browser API


- 웹 브라우저에 구현된 API이다.
- DOM event, AJAX, Timer 등이 있다.

 

이벤트 루프

- 콜 스택이 비었다면, 태스크 큐에 있는 콜백 함수를 처리한다. (이후 자세히 설명)

 

태스크 큐

- 비동기 함수(setTimeout, setInterval 등)는 처리 전 이곳에서 대기하게 된다. 
- 이벤트 루프는 하나 이상의 태스크 큐를 갖는다.
- 태스크 큐는 태스크의 Set이다.
- 이벤트 루프가 큐의 첫 번째 태스크를 가져오는 것이 아니라, 태스크 큐에서 실행 가능한(runnable) 첫 번째 태스크를 가져오는 것이다. 태스크 중에서 가장 오래된 태스크를 가져온다.

 

(태스크 큐 관련해서 Microtask Queue, Animation Frames라는 세부적인 개념도 있는데 생략한다)

 

참고)

https://velog.io/@titu/JavaScript-Task-Queue%EB%A7%90%EA%B3%A0-%EB%8B%A4%EB%A5%B8-%ED%81%90%EA%B0%80-%EB%8D%94-%EC%9E%88%EB%8B%A4%EA%B3%A0-MicroTask-Queue-Animation-Frames-Render-Queue

 

[JavaScript] Task Queue말고 다른 큐가 더 있다고? (MicroTask Queue, Animation Frames)

자바스크립트에서 비동기 함수가 동작하는 원리에 대해서 공부했다면, Task Queue에 대해 들어보았을 것이다. Task Queue는 Web API가 수행한 비동기 함수를 넘겨받아 Event Loop가 해당 함수를 Call Stack에

velog.io

 

싱글 쓰레드와 이벤트 루프

 

setTimeout같은 타이머는 JS 엔진이 아니라 외부에 구현되어 있다!

 

그리고, 자바스크립트가 단일 쓰레드 기반이라는 말이 정확히는 '자바스크립트 엔진'은 단일 호출 스택을 사용한다 라는 것이다.

 

위 그림같은 경우는 Node.js는 비동기 IO를 지원하기 위해 libuv 라이브러리를 사용하며, 이 libuv가 이벤트 루프를 제공한다. 브라우저에서는 Web API가 setTimeout 같은 함수를 지원하며, 타이머를 JS의 싱글 쓰레드가 아닌, 브라우저의 자체 쓰레드에서 세다가 자바스크립트의 테스크 큐에 넣어주게 된다. 

 

즉, 실제 자바스크립트가 구동되는 환경(브라우저, Node.js)는 여러개의 쓰레드를 사용하고, 이 다중 쓰레드 환경과 자바스크립트 엔진이 상호 연동하기 위해 내부적으로 이벤트 루프를 이용해 처리하게 된다.

 

(또 다른 예시로는 Node.js에서 I/O를 처리할때 자바스크립트의 싱글 쓰레드로만 동작하는게 아니고, 커널 쓰레드에서 처리하는것?이라 볼 수 있을것 같다?)

 

그럼 자바스크립트가 어떻게 비동기 함수를 처리하는지, 이벤트 루프를 어떻게 사용하는지 예시를 보자

 

function delay() {
    for (var i = 0; i < 100000; i++);
}
function foo() {
    delay();
    bar();
    console.log('foo!'); // (3)
}
function bar() {
    delay();
    console.log('bar!'); // (2)
}
function baz() {
    console.log('baz!'); // (4)
}

setTimeout(baz, 10); // (1)
foo();

 

위 코드를 작동시키면 setTimeout으로 타이머를 걸어놓은 baz가 정확히 10ms 이후에 실행되지 않는다.

 

그 이유는 자바스크립트가 비동기 함수를 지원하는 방식은 '이벤트 루프'를 사용해서 구현하고,

이벤트 루프는 '콜스텍에 현재 실행중인 task가 없는지'와 'task 큐에 태스크가 있는지'를 반복적으로 확인한다.

그리고 현재 실행중인 테스크가 없다면 이제서야 테스크 큐에 담겨있는 테스크를 꺼내와서 실행하게 되는것이다.

즉, 콜스택이 지금 바쁘다면 타이머 함수는 제 시간에 실행되지 않을 수 있다.

 

이를 하나의 함수가 실행이 완료되기 전에는 다른 함수가 실행될 수 없는 "Run to Completion" 라 부른다.

 

아래 코드 또한 좋은 예시이다.

let i = 0;

setTimeout(() => alert(i), 100); // ?

// 아래 반복문을 다 도는 데 100ms 이상의 시간이 걸린다고 가정합시다.
for(let j = 0; j < 100000000; j++) {
  i++;
}

실제 실행해보면 100000000이 나오게 된다.

 

(그나마?) 정확한 타이머를 구현하는 방법은?

 

(이 방법말고 다른 좋은 방법도 추천 받습니다!)

스택오버플로우 형님들의 경우는 아래의 코드와 비슷한 방식을 이용한다.

 

https://stackoverflow.com/questions/29971898/how-to-create-an-accurate-timer-in-javascript 

const interval = INTERVAL; // 1000ms
let time = Date.now() + interval;
let timerId = -1;

const exactlyTimeInterval = () => {
      const dt = Date.now() - time;
      time += interval;
		
      if (dt > interval) {
        // something really bad happened. Maybe the browser (tab) was inactive?
        // possibly special handling to avoid futile "catch up" run
        // 브라우저 말고 다른곳을 보고 있다면 브라우저의 타이머가 멈춰있고, 제대로 작동하지 않는다.
        // 그때 이 if문 안에 들어오게 된다
      }
      ...(생략)
      timerId = setTimeout(exactlyTimeInterval, Math.max(0, interval - dt));
    };
    
timerId = setTimeout(exactlyTimeInterval, interval);

 

setTimeout를 재귀적으로 실행하면 다음과 같이 function이 끝난 후 다음 계획을 실행한다.

setTimeout 예시

그래서 Date 객체의 now 값을 이용해서 실시간으로 다음 계획까지 걸리는 타이머를 보정받는다.

콜스택에 의해 지금 function의 실행이 늦었다면 다음 실행의 경우 늦은만큼 보정한다.

 

하지만 브라우저가 inactive(다른 화면을 보고있다던지)하게 되면 타이머는 정지되게 되고, 다시 브라우저가 활성화된다면 그때 황급히 카운트를 쭉 세게 된다.

 

100% 완벽한가? 까지는 아니지만 괜찮은 방법인거 같다.

 

함께 읽어보면 좋은 글)

 

운영체제의 프로세스 - 쓰레드 구조가 실제로 크롬 브라우저에서 어떻게 쓰이는지 

https://developers.google.com/web/updates/2018/09/inside-browser-part1?hl=ko 

 

모던 웹 브라우저 들여다보기 (파트 1)  |  Web  |  Google Developers

브라우저에서 사용자 코드를 하이레벨 아키텍처부터 렌더링 파이프라인 세부 기능에 이르는 기능성 웹사이트로 전환하는 방법

developers.google.com

 

reference 

 

https://meetup.toast.com/posts/89

 

자바스크립트와 이벤트 루프 : NHN Cloud Meetup

자바스크립트와 이벤트 루프

meetup.toast.com

 

https://velog.io/@yejineee/%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84%EC%99%80-%ED%83%9C%EC%8A%A4%ED%81%AC-%ED%81%90-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C-%ED%83%9C%EC%8A%A4%ED%81%AC-%EB%A7%A4%ED%81%AC%EB%A1%9C-%ED%83%9C%EC%8A%A4%ED%81%AC-g6f0joxx

 

이벤트 루프와 태스크 큐 (마이크로 태스크, 매크로 태스크)

자바스크립트는 싱글 스레드 기반의 언어이고, 자바스크립트 엔진은 하나의 호출 스택만을 사용한다. 이는 요청이 동기적으로 처리되어, 한 번에 한 가지 일만 처리할 수 있음을 의미한다. 만약

velog.io

 

https://ko.javascript.info/settimeout-setinterval

 

setTimeout과 setInterval을 이용한 호출 스케줄링

 

ko.javascript.info

https://stackoverflow.com/questions/29971898/how-to-create-an-accurate-timer-in-javascript

 

How to create an accurate timer in javascript?

I need to create a simple but accurate timer. This is my code: var seconds = 0; setInterval(function() { timer.innerHTML = seconds++; }, 1000); After exactly 3600 seconds, it prints about 3500 s...

stackoverflow.com

 

반응형

'Front-end > JavaScript' 카테고리의 다른 글

pnpm 도입기 (feat: 모노 레포)  (0) 2023.07.15
자바스크립트의 async/await에 대해서  (0) 2022.03.31
JS로 Single Page Application 구현  (0) 2022.03.12
Generator  (0) 2022.02.02
호이스팅과 var, let에 대하여  (0) 2022.01.29
반응형

폰 노이만 구조

현재와 같은 CPU, 메모리, 프로그램 구조를 갖는 범용 컴퓨터 구조의 확립

 

  • 산술 논리 장치와 프로세서 레지스터를 포함하는 처리 장치
  • 명령 레지스터와 프로그램 카운터를 포함하는 컨트롤 유닛
  • 데이터와 명령어를 저장하는 메모리
  • 외부 대용량 스토리지
  • 입출력 매커니즘

장점 

컴퓨터에 작업을 시키려고 할때 하드웨어적으로 재 배치를 할 필요가 없이 소프트웨어만 교체하면 되기 때문에

범용성(general-purpose)이 크게 향상된다.

따라서 현대의 컴퓨터는 거의 다 이 구조를 따르고 있다.

 

단점

메모리에서 데이터/코드(프로그램)을 가져올때 버스 하나로 한번에 하나만 가져오는 구조이기 때문에 폰 노이만 병목 현상이 일어날 수 있다.

이를 해결하기 위해 다양한 방법이 고안되었지만 폰 노이만 구조를 쓴다면 근본적 문제는 해결하진 못했다.

 

- 하버드 구조의 발명 

- 메모리 계층 구조(L1~L2 캐시, 메인 메모리, 하드디스크 구조)

- 다양한 방식 고안

ex) NUMA(메모리에 접근하는 시간이 메모리와 프로세서간의 상대적인 위치에 따라 달라진다.)

DMA(CPU가 직접 메모리 접근)

 

 

하버드 구조

하버드 아키텍처(Harvard architecture)는 명령용 버스와 데이터용 버스로 물리적으로 분할한 컴퓨터 아키텍처

명령용 버스와 데이터용 버스를 분할 -> 폰 노이반 병목 현상을 동시 접근으로 해결하려고 시도

 

단점 : cost(버스가 2배!)

 

현대에 이르러서는 CPU의 외부적으로는 폰 노이만 구조를, 내부적으로는 하버드 구조

 

reference

 

https://velog.io/@ckstn0777/%EC%BB%B4%ED%93%A8%ED%84%B0-%EA%B5%AC%EC%A1%B0

반응형

'CS > 컴퓨터구조' 카테고리의 다른 글

[컴퓨터 구조] cache, Write Through과 Write Back  (0) 2022.01.23
반응형

 

test 종류에 관한 이야기는 간략히 

 

https://lodado.tistory.com/category/%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4%EA%B3%B5%ED%95%99

 

'소프트웨어공학' 카테고리의 글 목록

https://github.com/lodado 이전 블로그 https://blog.naver.com/ycp998

lodado.tistory.com

에 적었다.

 

테스트가 좋다는건 많은 사람들이 알지만 제대로 된 테스트 케이스를 작성하는건 어려운것 같다.

 

TDD(Test Driven Development)란?

 

테스트가 개발을 이끌어 나간다.

기본 개발 방식은 요구사항 분석 -> 구현 -> 테스트라면 

TDD는 요구사항 분석 -> 테스트 -> 구현

 

그렇다면 TDD는 어떤 상황에서 해야할까?

처음해보는 프로그램 주제
나에 대한 불확실성이 높은 경우
고객의 요구조건이 바뀔 수 있는 프로젝트
외부적인 불확실성이 높은 경우
개발하는 중에 코드를 많이 바꿔야 된다고 생각하는 경우
내가 개발하고 나서 이 코드를 누가 유지보수할지 모르는 경우
즉, 불확실성이 높을 때 TDD를 하면 된다.

불확실성이 높다 -> 피드백 & 협력이 중요한 경우 

 

TDD 법칙

 

1. 실패하는 단위 테스트를 작성할 때까지 실제 코드를 작성하지 않는다.

2. 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다.

3. 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다.

중요한것은 지저분한 테스트코드는 안하느니만 못하다는 것이다.

중요도로 따지면 기능 === 테스트 코드이다.

 

좋은 테스트 코드는 유연성, 유지보수성, 재사용성을 제공한다. 

즉, 테스트 코드가 좋으면 변경이 쉬워진다.

리펙토링에 거부감이 없어진다.

 

 

깨끗한 테스트 코드란?

 

가독성이 좋은 코드

명료성, 단순성, 풍부한 표현력 (중복성 제거)

 

최소의 표현으로 많은것을 나타냄

 

BUILD-OPERATE-CHECK 패턴을 추천

 

1. BUILD - 테스트 자료

2. OPERATE - 테스트 조작

3. CHECK - 조작 결과 체크(boolean식으로 체크하는게 좋음)

 

도메인(DSL)에 특화된 테스트 언어

API 위에다 함수, 유틸리티 구현 후 사용(경계-분리 엄청 좋아하시는거 같다)

테스트 당사자와 독자를 도와주는 테스트 언어

 

이중 표준

제한된 자원, 환경적 문제로 인해서

테스트 코드가 기능 코드랑 똑같은 환경, 컨벤션일 필요는 없다.

(mocking 관련?)

 

테스트당 개념 하나

 

테스트당 assert 하나라는 개념도 있다.

그것도 나쁘지는 않지만 저자는 기능 '하나'당 테스트 '하나' 추천

 

F.I.R.S.T 개념

 

Fast

테스트는 빠르게

(tmi로 cypress보다는 jest가 당연히 빠르고, 느리면 테스트를 주저하게됨)

 

Independent

각 테스트는 서로 의존적이지 않다.

독립된 환경설정

이유 : 독립되야 어디서 진짜 문제가 생겼는지 알기 쉽다 

 

Repeatable

어느 환경에서도 반복 가능, 동일한 결과

 

Self-Validating

bool 값으로 테스트 결과를 내야한다.

테스트를 파헤치지 않아도 결과를 알 수 있어야 한다.


Timely

테스트를 적시에 작성

단위 테스트는 테스트하려는 실제 코드를 구현하기 직전에 구현

 

결론

 

사실 '테스트' 라는 주제 하나만으로도 책 한권을 쓸 정도로 어려운 부분이다.

테스트 코드는 실제 코드만큼 중요하다

 

개인적 경험으로는 프로젝트때 테스트 코드를 한번 도입해보려고 시도했는데 

무작정 도입하고 보니 '깨끗하지 않은 테스트 코드'의 표본이 된거 같아서

이 글에서 말한 없느니만 못한 테스트가 된거 같기도 하다 😂

 

그래서 요즘 괜찮은 테스트를 짜기 위해 이론적으로 공부중이다.

 

테스트는 개인적으로 팀원간의 '공유 작업 파트'를 변경시 문제점을 빨리 캐치하고

커뮤니케이션 비용을 줄이는 측면에서 큰 도움이 된다고 생각되고,

또한 리펙토링의 거부감을 줄이는데 이점이 있다고 생각된다.

 

그밖의 tmi)

 

tistory에서 글자 색깔을 바꿀 수 있는걸 배웠다!

 

reference 

 

https://gmlwjd9405.github.io/2018/06/03/agile-tdd.html

 

[Agile] TDD(테스트 주도 개발)란 - Heee's Development Blog

Step by step goes a long way.

gmlwjd9405.github.io

 

반응형

'독서 > cleancode' 카테고리의 다른 글

cleancode - class  (0) 2022.02.26
clean code - 경계  (0) 2022.01.24
cleancode - 오류처리  (0) 2022.01.22
cleancode - 객체와 자료구조  (0) 2022.01.21
clean code - 주석 & 형식 맞추기  (0) 2022.01.20
반응형

 

 

 

테스트의 종류

Unit Test

테스트할 수 있는 가장 작은 단위(함수)로 기능을 쪼개서 테스트하는 방식

만약 문제가 일어난다면 어디서 일어나는지 가장 효과적으로 알 수 있다.

가장 좋은 방식이라 생각되는 테스트

 

도구) jest, mocha 등 사용

 

보통 jest의 경우는 프론트는 프론트만, 백엔드는 백엔드의 기능만 테스트하고 다른 부분은 mocking해서 

정상적으로 동작한다고 가정하고 해당 'Unit'만 테스트하는 방식이다.

 

-> 기능 테스트 위주로 하는거 추천?

 

Intergration Test

 

말 그대로 코드들을 '통합' 해서 문제가 없는지 확인하는 테스트

보통은 협업할때 내 코드와 팀원의 코드가 결합되도 문제가 없는지 확인하는 테스트이다.

커뮤니케이션적인 측면이 많이 필요한 테스트라 생각이 든다

 

도구) jest, cypress 등 사용

 

E2E(End-To-End) test

유저의 입장에서 내가 만든 프로그램이 의도대로 제대로 작동하는지 확인하는 테스트 

front, backend 전부 하나로 묶어서 테스트하고 실제 배포전에 문제를 발견하기 가장 쉬운 방법이지만

'어디서' 문제가 발견되는지는 까다로울 수 있다. (front인지 backend인지, 기능 여러개를 묶었다면 어디서 오류가 발생된건지 E2E test만으로는 발견하기 어려울 수 있음)

 

따라서 E2E test 만 하는것보다는 Unit test와 병행해서 하는것을 추천한다.

 

도구) 셀레니움, cypress 등 사용

 

-> UI 테스트는 E2E로 하는거 추천?

 

좋은 테스트의 비율?

 

구글 컨퍼런스에 따르면, 

Google often suggests a 70/20/10 split: 70% unit tests, 20% integration tests, and 10% end-to-end tests. 

라고 한다.

 

그외 팁으로는 

  • 기존의 레거시 코드는 E2E 테스트로 커버하라.
  • 새로 개발하거나 변경하는 부분을 대상으로 우선적으로 단위 테스트를 시작하라.

E2E 테스트 또한 기능이 복잡하거나 중요한 기능부터 커버하기 시작하면 효율적으로 단위테스트 적용이 가능할 것이다.

 

TEST의 장점

- 리펙토링시 test가 안정성을 담보하므로 거침없이 리펙토링을 할 수 있다.

- 코드 변경으로 어떤 부분이 영향이 있는지 빨리 파악 가능하다

- 테스트 자동화시(CI) 실수를 빨리 캐치하고 커뮤니케이션 비용을 줄일 수 있다.

- 버그 수정에 드는 시간을 줄일 수 있다

- test를 짜는데 초반엔 시간이 많이 들어도 장기적으로 보면 시간을 절약할 수 있다.

TEST의 단점

살충제 패러독스 

 

동일한 테스트 케이스를 사용하여 반복적으로 테스트를 수행하면 새로운 버그를 찾지 못한다.

소프트웨어는 복잡계이고, 테스트를 다 통과했다고 완벽한 소프트웨어는 아니다.

내가 예상치 못한 부분에 버그가 숨겨져 있을 수 있다.

 

- 러닝 커브

- 팀이 테스트에 대해 미적지근한 반응이라면 이도저도 안될수도 있음

 

같이 보면 좋을 동영상)

 

https://www.youtube.com/watch?v=jdlBu2vFv58 

 

reference 

 

https://codeahoy.com/2016/07/05/unit-integration-and-end-to-end-tests-finding-the-right-balance/

 

Unit, Integration and End-To-End Tests - Finding the Right Balance

Explore the difference between unit, integration and end-to-end tests and how to choose between them.

codeahoy.com

 

https://www.popit.kr/unit-test-%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%8F%84%EC%9E%85%ED%95%98%EA%B8%B0-1%ED%8E%B8/

 

Unit Test (단위 테스트) 도입하기 - 1편 | Popit

원문 블로그 주소 : https://gregor77.github.io/2019/08/16/about-unit-test/ 관련글 : https://www.popit.kr/unit-test-단위-테스트-도입하기-2편/ 지금 부서의 역할이 사내에서 제품을 가지고 있는 팀들과 협업을 하면서

www.popit.kr

 

반응형
반응형

시스템에 들어가는 모든 소프트웨어를 직접 개발하는 경우는 드물다

이 장에서는 소프트웨어 경계를 깔끔하게 처리하는 기법과 기교를 살펴본다.

 

외부 코드 사용하기


더 많은 환경에서 돌아가야 더 많은 고객이 구매하니까 패키지 제공자나 프레임워크 제공자는 적용성을 최대한 넓히려 애쓴다. 반면 사용자는 자신의 요구에 집중하는 인터페이스를 바란다. 

이런 차이로 시스템 경계에 문제가 생길 소지가 많다.

 

ex) java.util.Map

 

설명이 완전히 java적인 내용이긴 한데.. 뭘 의미하고 있는지를 알아두면 좋을것 같다.

 

Map은 다양한 인터페이스로 수많은 기능을 제공한다.

이러한 기능성과 유연성은 확실히 유용하지만

Map을 그대로 넘긴다는 뜻은 예를들어 Map 내용을 지우는 clear()함수를 누구나 지울 권한을 가질 수 있다는 뜻과 같다.

 

Map sensors = new HashMap(); 
Sensor s = (Sensor) sensors.get(sensorId);

또한 위와 같이 Map을 올바른 유형의 Object로 변환할 책임은 Map을 구현한 곳이 아닌 실제로 사용하는 클라이언트 쪽에 있게 된다.

또한 의도가 드러나지 않는다. 대신 다음과 같이 Generics를 사용하면 코드 가독성이 크게 높아진다.

Map<String, Sensor> sensors = new HashMap<Sensor>();
Sensor s = sensors.get(sensorId);

하지만 여전히 사용자가 필요하지 않은 기능까지 넘기는것이 좋지 않다.

 

다음과 같이 제네릭스 사용 여부라던지 경계 인터페이스인 Map을 Sensor 클래스 안에 숨겨보자.

public class Sensors { 
	private Map sensors = new HashMap();
    
	public Sensor getById(String id) { 
	return (Sensor) sensors.get(id);
	} 
}

 

그러면 Map 인터페이스가 변하더라도 Sensor 클래스 안에서 객체 유형을 관리하고 변환할 수 있게 된다.

또한, 필요한 인터페이스만 제공할 수 있게 된다.

 

경계 살피고 익히기

 

외부 코드를 익히기는 어렵다. 외부 코드를 통합하기도 어렵다. 만약 곧바로 우리쪽 코드를 작성해 외부 코드를 호출하는 대신 먼저 간단한 테스트 케이스를 작성해 외부 코드를 익히면 어떨까?

 

학습 테스트 는 프로그램에서 사용하려는 방식대로 외부 API를 호출한다. 통제된 환경에서 API를 제대로 이해하는지를 확인하는 셈이다. 학습 테스트는 API를 사용하려는 목적에 초점을 맞춘다.

 

학습 테스트는 공짜 이상이다.

 

학습 테스트는 이해도를 높여주는 정확한 실험이다.

학습 테스트에 드는 비용은 없고 필요한 지식만 확보하는 쉬운 방식이다.

 

패키지가 새로운 버젼이 나오면 학습 테스트를 돌려 차이가 있는지 확인한다.

새 버젼이 호환되지 않으면 바로 학습 테스트가 밝혀낸다.

 

이런 테스트가 존재한다면 어느 부분이 호환성 문제가 생기는지 빨리 밝혀내고 새 버젼으로 빨리 이전하기 쉬워진다.

 

아직 존재하지 않는 코드를 사용하기

경계와 관련해 또 다른 유형은 아는 코드와 모르는 코드를 분리하는 경계다.

 

ex) 저쪽 팀이 아직 API를 설계하지 않았으므로 구체적인 방법은 모를때
구현을 미루고 이쪽 코드를 진행하기 위해 자체적으로 인터페이스를 정의한다.

 

어뎁터 패턴을 이용해서 다른 팀이 개발하고 있는 코드를 분리하고, API 사용을 캡슐화해 API 바뀔때 수정할 코드를 한곳으로 모은다.

(부가적으로 테스트도 쉬워짐)

 

깨끗한 경계

 

통제하지 못하는 코드(오픈소스나 외부 라이브러리 등)를 사용할때는 주의해야한다.

경계에 위치하는 코드는 깔끔히 분리한다.

 

이쪽에서 상대 코드를 세세히 알 필요는 없다. 외부패키지에 의존하지 말고 통제가 가능한 우리 코드에 의존한다.

외부 패키지를 호출하는 코드를 가능한 줄여 경계를 관리하자.

 

Adapter pattern을 사용하던지 위에서 보았던것처럼 새로운 클래스로 경계를 감싸서 우리가 인터페이스를 만들어 제어하자.

 

 

핵심 

 

-> 외부 라이브러리와 맞닿는 부분은 직접 쓰지말고 인터페이스 같은 방식으로 분리하고, 주도적으로 제어

이 파트는 좀 심오한 내용인것 같다.. 

일단 '분리' 자체에는 동의한다.

반응형

'독서 > cleancode' 카테고리의 다른 글

cleancode - class  (0) 2022.02.26
cleancode - unit test  (0) 2022.01.25
cleancode - 오류처리  (0) 2022.01.22
cleancode - 객체와 자료구조  (0) 2022.01.21
clean code - 주석 & 형식 맞추기  (0) 2022.01.20
반응형

 

캐시란?

 

자주 사용하는 데이터나 값을 미리 복사해 놓는 임시 장소를 가리킨다. 캐시는 저장 공간이 작고 비용이 비싼 대신 빠른 성능을 제공한다. 

 

Cache는 아래와 같은 경우에 사용을 고려하면 좋다.

  • 접근 시간에 비해 원래 데이터를 접근하는 시간이 오래 걸리는 경우(서버의 균일한 API 데이터)
  • 반복적으로 동일한 결과를 돌려주는 경우(이미지나 썸네일 등)

캐시는 컴퓨터 구조뿐만 아니라 네트워크, DB등 여러곳에서 자주 사용하는 개념이다.

이글에서는 CPU 내부의 캐시에 대해 간략하게 알아본다.

 

CPU 캐시 란

 

cpu의 내부 캐시란 CPU와 메인 저장 장치(하드디스크)간 속도의 모순을 해결하기 위해서 사용하는 것이다.

 

CPU 는 종종 동일한 데이터를 반복적으로 처리하고, 실행하는데(지역성) 그때마다 메모리에서 받아와 처리한다면 

비교적 느린 하드디스크에서 데이터를 받아올때마다 CPU는 기다리는 오버헤드가 발생하게 된다.

 

그래서 CPU 내부에 일종의 저장 장소(SRAM)를 가지고 캐싱해놓게 되는데 그것을 캐시라 한다.

 

L1, L2, L3 캐시 메모리등이 있는데

숫자가 작을수록 작고 비싸고, 빠르고 CPU 내부에서 가장 가까운 곳에 위치해 있다고 보면 된다.

 

그리고 cache를 제어하는 방식에 대해 간단히 알아보자.

 

write-Through

CPU가 데이터를 사용하면 캐시에 저장되게 되는데, 데이터가 캐시 됨과 동시에 주기억장치 또는 디스크로 기입되는 방식을 지원하는 구조의 캐시이다. 즉, 캐시와 메모리 둘다에 업데이트를 해버리는 방식이다.

 

다만 업데이트때마다 직접 하면 cost가 비싸므로 

Write buffer라는 구조를 사용해서 CPU 프로세서가 직접 Write 명령을 수행하지 않아 대기하는 시간을 줄여주는 방식으로 작동한다고 한다. (이건 write Back에도 사용 가능)

 

write-Back

 데이터를 쓸 때 메모리에는 쓰지 않고 캐시에만 업데이트를 하다가 필요할 때에만 주기억장치나 보조기억장치에 기록하는 방법이다.

 

그럼 캐싱을 사용하면 안될때는 언제일까?

C언어, Java에서는 volatile 명령어로 캐싱을 사용하지 않고 메인메모리에서 접근해서 가져오도록 사용 가능하다.

volatile int num1 = 10;    // 변수를 최적화에서 제외하여 항상 메모리에 접근하도록 만듦
public class SharedObject {
    public volatile int counter = 0;
}

 

그럼 이것을 언제 사용할까?

캐시는 지금까지 좋다고 글을 썼는데 왜 캐시를 안쓰고 굳이 메인 메모리에서 값을 가져올까?

그 답은 아래 그림처럼 멀티 CPU 상황일경우 임계영역인 데이터의 동기화를 위해 쓴다고 볼 수 있다.

 

혹은 임베디드 프로그래밍에서 인터럽트 내부에서 메모리의 어떤 값이 수정되었는데 CPU 내부의 캐시는 수정되지 않았을때를 방지하려고 volatile 예약자를 쓴다. 

 

읽어보면 좋을 글)

https://blog.naver.com/cjsksk3113/222253156868

 

캐시 일관성(Cache Coherence)과 캐시 속성(Cacheable / Non Cacheable)

캐시 메모리 요즘의 CPU 주기억장치 메모리(Main Memory)는 거의 100% SDRAM으로 구성된다. SD...

blog.naver.com

 

reference 

 

https://itgall.com/hardware/232948

 

CPU 캐시가 L1, L2 및 L3으로 나뉘는 이유에 대해 알아보자

캐시라는 용어는 누구나 들어봤을 것입니다. 사실 캐시의 의미는 매우 광범위합니다. 컴퓨터에서 가장 큰 캐시는 메모리 스틱으로 구현할 수 있고 그래픽 카드의 비디오 메모리는 그래픽 칩에

itgall.com

 

https://mangkyu.tistory.com/69

 

[Server] Cache(캐시)란?

1. 캐시(Cache)란? [ Cache ] Cache란 자주 사용하는 데이터나 값을 미리 복사해 놓는 임시 장소를 가리킨다. 아래와 같은 저장공간 계층 구조에서 확인할 수 있듯이, 캐시는 저장 공간이 작고 비용이

mangkyu.tistory.com

https://nesoy.github.io/articles/2018-06/Java-volatile

 

Java volatile이란?

 

nesoy.github.io

https://blog.naver.com/PostView.nhn?blogId=cjsksk3113&logNo=222282586535 

 

캐시 메모리의 쓰기 정책 : Write-Through, Write-Back

캐시 메모리는 CPU 프로세서의 동작을 돕기 위한 임시 메모리 저장소이다. 따라서 CPU 프로세서가 캐...

blog.naver.com

 

반응형

'CS > 컴퓨터구조' 카테고리의 다른 글

[컴퓨터구조] 하버드 구조와 폰 노이만 구조  (0) 2022.01.26
반응형

3-way handshake와 4-way handshake는 TCP 프로토콜에서 연결을 시작/종료할때 쓰는 방식이다.

우선 TCP부터 알아보자.

 

TCP

TCP란 연결 지향적 프로토콜로 데이터패킷을 주고받을때 신뢰성을 보장한다.

 

그외 특징으로는

  • 흐름 제어, 혼잡 제어, 오류 제어
  • UDP보다 느린 대신 OSI 4계층(transport)에서 신뢰성 보장
  • 파일을 분할해서 전송(MSS)
  • 연결형 서비스로 가상 회선 방식을 제공

신뢰성을 보장하는 방식으로는 패킷을 보낸 후, 수신 확인(ACK)를 받는다.

제한시간내에 ACK가 오지 않는다면 패킷이 네트워크 중간에 손실되었다고 가정하고 다시 보낸다.

따라서 해당 방식때문에 신뢰성을 보장하지만 느리다.

(혼잡제어나 패킷을 보내는 방식은  흥미로운 부분이라 나중 글을 관련 부분으로 더 쓸 예정)

 

3-way handshake

연결하기 위해 두 장치의 논리적 접속을 성립하기 위해 사용하는 연결 확인 방식이다.

3번의 확인을 거친다고 해서 3 way handshake라 부른다

 

tmi) 4계층(transport)는 host 프로세스와 guest 프로세스 간 양 호스트 종단의 논리적 통신을 보장하고,

3계층(network)는 host와 guest 간 논리적 통신을 보장한다.

 

 

접속 시도시 client는 SYN 패킷을 보내 server에 접속 요청을 보낸다.

서버는 SYN 패킷을 받으면 접속이 가능하다는 의미로 client에세 SYN과 ACK 패킷을 보낸다.

client는 서버에세 SYN+ACK 패킷을 받았다면 이제 통신을 시작했다는 의미로 ACK를 보내고,

통신을 시작한다.

 

SYN (synchronize sequence numbers) - 연결 확인을 위해 보내는 무작위의 숫자값

ACK (acknowledgements) - Client 혹은 Server로부터 받은 SYN에 1을 더해 SYN을 잘 받았다는 ACK

ISN (Initial sequence numbers) - Client와 Server가 각각 처음으로 생성한 SYN

 

- SYN의 값에 무작위 수를 사용하는 이유?

  • Connection을 맺을 때 사용하는 포트는 유한 범위 내에서 사용하고 시간이 지남에 따라 재사용된다. 따라서 두 통신 호스트가 과거에 사용된 포트 번호 쌍을 사용할 가능성이 존재한다. 서버 측에서 패킷의 SYN을 보고 패킷을 구분하게 되는데 난수가 아닌 순차적인 숫자가 전송된다면 이전의 connection으로부터 오는 패킷으로 인식할 수 있어 이러한 문제 발생 가능성을 줄이기 위해 ISN을 무작위 난수로 사용하는 것이다.

 

4-way handshake

4-way handshake는 반대로 가상 회선 연결을 해제할때 주고 받는 확인 작업이다.

4번의 확인과정을 거친다고 하여 4 way handshake라고 부른다.

 

흔히 client가 close를 요청하고, server가 확인하고 닫는다고 알려져 있는데

서버도 close를 요청할 수 있다.

그래서 먼저 4-way handshake를 요청하는 쪽을 Active Closer, 받는 쪽을 Passive Closer라 한다.

 

과정을 요약하자면

 

Active closer가 먼저 서버를 닫고 싶다는 FIN 요청을 보내고 FIN-wait 상태에 들어간다.

그럼 Passive closer는 알았다는 ACK를 보내고, close-wait 상태에 들어간다.

그리고 Passive closer는 통신을 종료할 준비가 완료되면 FIN 을 다시 Active closer에 보낸다.

Active Closer는 FIN을 받았으면 time-wait 과정에 들어가고 ACK를 passive closer에게 보낸다. 

passive closer는 ACK를 받으면 통신을 종료한다.

active closer는 time wait상태에서 대기하다가 통신을 종료한다.

 

 

time wait는 

 

먼저 연결을 끊는 (active closer) 쪽에 생성되는 소켓으로, 혹시 모를 패킷 전송 실패에 대비하기 위하여 존재하는 소켓이다.

time-wait가 없다면 패킷의 손실이 발생하거나 통신자 간 연결 해제가 제대로 이루어지지 않을 수 있다.

 

 

읽어보면 좋을 글)

 

3 way handshake의 과정을 악용한 SYN flooding attack(보안)

https://run-it.tistory.com/51

 

SYN Flooding이란?

안녕하세요 여러분! IT 세계에는 다양한 분야가 존재합니다. 멀고 먼 험난한 길이지만... 우리는 지금까지 네트워크 영역을 다루고 이제 보안 영역에 들어와 계속해서 순항중에 있습니다. 비록

run-it.tistory.com

 

reference

 

https://seongonion.tistory.com/74

 

[네트워크] TCP 3-way & 4-way handshake란?

TCP란 연결 지향형 프로토콜로, 연속성 있는 데이터 패킷을 주고 받을 때 사용한다. TCP 특징 전송되는 데이터의 신뢰성 보장 (흐름 제어, 혼잡 제어, 오류 제어) 파일전송에 주로 사용 가상 회선을

seongonion.tistory.com

 

https://tech.kakao.com/2016/04/21/closewait-timewait/

 

CLOSE_WAIT & TIME_WAIT 최종 분석

트래픽이 많은 웹 서비스를 운영하다보면 CPU는 여유가 있지만 웹서버가 응답을 제대로 처리하지 못하고 먹통이 되는 경우를 종종 보게 됩니다. 여러가지 이유가 있겠지만, 이 글에서는 가장 대

tech.kakao.com

 

 

반응형

'CS > 네트워크' 카테고리의 다른 글

AnyCast란?  (0) 2022.04.11
URL & URI & URN  (0) 2022.02.27
HTTP 메소드 멱등성, 안전한 메소드  (0) 2022.01.31
Pooling, Long Pooling, Streaming  (0) 2022.01.23

+ Recent posts