Giter Site home page Giter Site logo

til's Introduction

Tech Stack


til's People

Contributors

hon9g avatar

Stargazers

 avatar

Watchers

 avatar

Forkers

brojohnny

til's Issues

브라우저에 URL을 입력하면?

1. DNS를 통해 서버 아이피주소 파악하기

브라우저는 DNS에 요청하여 도메인이 해당하는 아이피 주소 얻어낸다.

2. 브라우저와 서버가 3 Way Handshake

브라우저와 서버는 3 Way Handshake 을 한다.

  1. 브라우저가 어떤 번호를 서버에 전달.
  2. 서버는 그 번호에 1을 더하여 클라이언트에 전달.
  3. 브라우저는 응답받은 번호에 또 1을 더하여 서버에 전달.

어떤 번호 = Random Sequence

3. 브라우저에 서버가 HTTP Request

브라우저는 서버에 HTTP Request를 보내 필요한 자원을 받는다.

4. HTTP Response

서버는 브라우저에게 HTML, JS, CSS 등 화면 렌더링에 필요한 자원을 보내준다.

5. 렌더링

1. Construction

  • HTML을 파싱하여 DOM Tree 생성. DOM 트리란 HTML 문서에 적혀있는 element들을 Tree 구조의 데이터로 만든 것.
  • HTML을 파싱하다 <script> 태그를 통해 CSS 파일을 로드한 코드를 만나면 HTML파싱을 멈춘다. CSS 코드를 해석하여 CSSOM을 만든다. 접근한 CSS 코드의 파싱이 끝나면, 다시 HTML 파싱 작업으로 돌아온다.
  • HTML을 파싱하다 <script> 태그를 통해 JS 코드 또는 JS 파일을 로드한 코드를 만나면 HTML 파싱을 멈춘다. 자바스크립트 엔진에게 권한을 넘겨 JS를 해석하여 AST를 생성하고 실행.
  • 서버에 추가 데이터를 요청했을 경우, HTML에서는 등 JS에서는 async 등 비동기적으로 동작하도록 했다면, 서버에서 데이터가 도착할 때까지 기다리지 않고 화면을 렌더링한다.
  • DOM, CSSOM, AST 생성이 끝나면, Render Tree를 만든다. Render Tree란 화면에 곧바로 출력할 HTML element와 그에 해당하는 스타일을 포함한 데이터를 말한다. DOM과 CSSOM을 조합하여 만든다. DOM + CSSOM = RenderTree (근데 화면에 보여지는 요소만)

2. Operation

1. Layout

렌더링엔진이 Render Tree에 있는 노드들을 배치. (x, y 배치)

2. Painting

Render Tree에 있는 노드들에 UI를 그림.

3. Composition (마지막)

z-index에 맞춰 화면을 구성.

3. Display

브라우저는 최종적으로 사용자에게 화면을 표시함.

클로저

실행이 종료된 스코프의 지역 변수를 참조할 수 있는 현상.

어떤 함수 A에서 선언한 변수 x를 참조하는 내부함수 B를 외부로 전달할 경우, A의 실행 컨텍스트가 종료된 이후에도 변수 x가 사라지지 않는 현상.

React: Starter Package

  • We built React to solve one problem:
    • building large applications with data that changes over time.
  • Approach:
    • mutation 을 하지말고 그냥 기존의 view 를 날려버리고 새로운 view 를 만들면 어떨까?
    • DOM 기반 브라우저에서 매번 새로운 view를 그리면 성능적으로 문제가 생기므로
    • Virtual DOM 에 일단 view를 그려보고 바뀐 부분만 실제 DOM에 patch 해준다.
    • https://www.youtube.com/watch?v=muc2ZF0QIO4
  • Why need React
    • A javaScript library (means it is not heavy)
    • for building user interfaces
    • React is declarative

JavaScript: Functions

Function

  • JavaScript에서 function은 first-class Object입니다.
  • function는 호출될 수 있다는 점에서 다른 Object 와 구분된다.
  • functionFunction Object 입니다.

Traditional JavaScript

function myFunction () {}
myFunction = function () {}
  • variable myFunction contain function.
  • variable places in global scope, attached to the topmost object within DOM.
    • It is risky because of
    • Globally defined values are available to any script running from within any section of current page.
    • Any libraries that have been loaded could overwrite your original code.
    • It would be hard to debug
var name = function () {}
  • var keyword
    • JavaScript to limit the scope of the function to the current containing code block,
    • usually the script tag within an HTML page.
    • In this case function won't be used in any other library.
var myObject = { myFunction: function () {} }
  • Function in a single Object
    • nice encapsulation
    • promote reusability
  • var keyword
    • can not used this function globally
    • only can be used in code block scope
myObject = { myFunction: function () {} }
  • single global object with a unique name
    • can be used function globally
    • avoid conflict with loaded libraries.

Reduct: Reselect

Deriving Data with Selectors

리덕스 문서에 목차 Deriving Data with Selectors를 보면 Selector들의 목적과 동기, 왜 memoized Selector들이 유용한지, 일반적인 Reselect 사용 패턴, React-Redux에서의 Selector 사용법을 다룹니다.

Deriving Data

Redux 어플리케이션에서 state는 최소한으로 유지하고, 언제든지 가능할 때에 추가적인 값들을 state에서 파생시키는 것을 추천합니다.
여기에는 필터링된 목록 연산과 값들을 합산하는 연산 또한 포함됩니다.

이러한 방식의 장점은 다음과 같습니다.

  • 실제 state를 더 읽기 쉽습니다.
  • (state로 부터 파생될 수 있는) 추가적인 값들을 계산하고 나머지 데이터와 동기화된 상태로 유지하는 데 필요한 로직을 덜어낼 수 있습니다.
  • original state는 여전히 참조로 존재하며 대체되지 않습니다.

Calculating Derived Data with Selectors

일반적인 Redux 애플리케이션에서 데이터를 파생시키는 로직은 일반적으로 Selector라고 하는 함수로 작성됩니다.

Selector들은 다음의 로직을 캡슐화하는데에 사용됩니다.

  • state에서 특정 값을 조회하기 위한 논리.
  • 실제로 값을 파생하기 위한 논리.
  • 불필요한 재연산을 방지하여 성능을 개선하기 위한 논리.

모든 state 조회에 Selector를 사용할 필요는 없지만, 이는 표준 패턴이며 널리 사용됩니다.

Selector의 기본 컨셉

"selector function"은the Redux store state (or part of the state)를 인자로 받고, state를 기반으로 한 데이터를 반환하는 (아무) 함수를 말합니다. Selector들은 특별한 라이브러리를 통해 작성될 필요가 없습니다. 또한, 화살표 함수로 작성하든, function 키워드를 통해 작성하든 전혀 상관 없습니다.

아래의 함수들은 모두 Selector 입니다.

// Arrow function, direct lookup
const selectEntities = state => state.entities

// Function declaration, mapping over an array to derive values
function selectItemIds(state) {
  return state.items.map(item => item.id)
}

// Function declaration, encapsulating a deep lookup
function selectSomeSpecificField(state) {
  return state.some.deeply.nested.field
}

// Arrow function, deriving values from an array
const selectItemsWhoseNamesStartWith = (items, namePrefix) =>
  items.filter(item => item.name.startsWith(namePrefix))

Optimizing Selectors with Memoization

Selector 함수는 종종 상대적으로 "비싼" 계산을 수행하거나 새로운 객체 및 배열 참조들인 파생 값을 생성해야 합니다. 다음과 같은 몇 가지 이유로 애플리케이션 성능에 문제가 될 수 있습니다.

  • useSelector 또는 mapState와 함께 사용되는 Selector들은 Redux root state의 어떤 섹션이 실제로 업데이트되었는지에 관계없이 모든 dispatch된 action 후에 다시 실행됩니다. input state 섹션들이 변경되지 않았을 때, 값비싼 계산을 다시 실행하는 것은 CPU time 낭비입니다. 그리고 input의 대부분이 변경되지 않을 가능성이 매우 높습니다.
  • useSelectormapState는 반환 값에 대해 === reference equality 검사에 의존하여 컴포넌트를 다시 렌더링해야 하는지 여부를 결정합니다. 만약 selector가 항상 새 참조를 반환하는 경우, 파생된 데이터가 이전 것과 사실상 동일하더라도 컴포넌트가 강제로 다시 리렌더링됩니다. 일반적으로 이는 새 배열 참조를 반환하는 map(), filter()와 같은 배열 조작에서 발생합니다.

이 때문에 동일한 입력이 전달되는 경우 결과를 다시 계산하는 것을 피할 수 있는 최적화된 selector�들을 작성하는 방법이 필요합니다. 이 필요가 memoization에 대한 아이디어가 나오게된 동기입니다.

Memoization은 caching의 한 형태입니다. 여기에는 함수에 대한 입력을 추적하고, 나중에 참조할 수 있도록 입력들과 �결과들� 저장하는 작업이 포함됩니다. 이전과 동일한 입력으로 함수를 호출하면, 함수는 실제 작업을 건너뛸 수 있으며, 해당 입력 값을 마지막으로 받았을 때 생성한 것과 동일한 결과를 반환할 수 있습니다. 이렇게 하면 입력이 변경된 경우에만 작업을 수행하고 입력이 동일한 경우 동일한 결과 참조를 일관되게 반환하여 성능을 최적화합니다.

Writing Memoized Selectors with Reselect

Reselect는 memoized selector를 작성하기 위해 Redux 생태계에서 오랫동안 사용해온 라이브러리입니다.

createSelector Overview

Reselect는 memoized selector들을 생성하기 위해 createSelector라는 함수를 제공합니다. createSelector는 하나 이상의 "input selector" 함수와 "output selector" 함수를 인자로 받고, 사용할 수 있는 새로운 selector 함수를 반환합니다.

createSelector는 input selector를 인자로 받을 때 개별 인수들로 받을 수도 있고, 또는 한 개의 배열로 받을 수도 있습니다. 모든 input selector들의 결과 값들은 output selector에 별도의 인수들로 제공됩니다.

const selectA = state => state.a
const selectB = state => state.b
const selectC = state => state.c

const selectABC = createSelector([selectA, selectB, selectC], (a, b, c) => {
  // do something with a, b, and c, and return a result
  return a + b + c
})

// Call the selector function and get a result
const abc = selectABC(state)

// could also be written as separate arguments, and works exactly the same
const selectABC2 = createSelector(selectA, selectB, selectC, (a, b, c) => {
  // do something with a, b, and c, and return a result
  return a + b + c
})

Selector를 호출하면 Reselect는 사용자가 인수로 제공한 모든 input selector들을 실행하고 반환된 값을 확인합니다. 결과 중 하나라도 === 이전과 다른 경우, input selector들의 새로운 결과를 output selector에 인수로 전달하며 재실행시킵니다. input selector들의 모든 결과값이 이전의 값과 같으면 output selector 재실행을 건너뛰고 이전의 캐시된 최종 결과만 반환합니다.

이는 input selector에서는 항상 값을 추출해야하고, output selector에서는 데이터를 transformation하는 작업을 해야만 한다는 말 입니다.

Reselect

Reselect 는 memoized "selector" function들을 생성하기 위한 라이브러리이다. 주로 리덕스와 사용되며, 공식 Redux Toolkit Package에 이미 포함되어있다.(별도 install 필요없음) 별개로 그냥 불변 JS 데이터에도 사용할 수 있다.

  • Selector들은 파생된 데이터(derived data)를 계산하여 Redux가 가능한 최소 상태를 저장할 수 있도록 합니다.
  • Selector들은 효율적입니다. Selector는 인수 중 하나가 변경되지 않는 한 다시 계산되지 않습니다.
  • Selector들은 구성 가능(composable)합니다. 한 Selector는 다른 Selector에 대한 입력으로 사용할 수 있습니다.

react-router Router, Route, Link 카피하기

React & History API를 사용하여 SPA Router 기능 구현하려고 한다.
구현에 앞서 이미 잘 구현되어있는 라이브러리 react-router 의 코드가 어떻게 작성되어 있는지 확인해보려고 한다.

JavaScript: use strict

  • 'use strict';
    • JavaScript to throw errors in places use strict;would,
    • otherwise, just silently fail.

CSS: layout

Layout could done with floats or positioning

GraphQL spec

GraphQL은 단순히 specification으로 출시되었다.

  1. How to build GraphQL server - you can implement it with your preferred language
  2. First of all, you should design a schema

Why React

  • We built React to solve one problem:
    • building large applications with data that changes over time.
  • Approach:
    • mutation 을 하지말고 그냥 기존의 view 를 날려버리고 새로운 view 를 만들면 어떨까?
    • DOM 기반 브라우저에서 매번 새로운 view를 그리면 성능적으로 문제가 생기므로
    • Virtual DOM 에 일단 view를 그려보고 바뀐 부분만 실제 DOM에 patch 해준다.
    • https://www.youtube.com/watch?v=muc2ZF0QIO4
  • Why need React
    • React is a declarative, efficient, and flexible
    • javaScript library (means it is not heavy)
    • for building complex user interfaces
    • from small and isolated pieces of code called “components”.

JavaScript: map, reduce, filter

Array.prototype.map()

  • map() method creates new array

example 1.

const arr = [ 0, 1, 2, 3 ];
const m = arr.map( x => x**2 );

console.log(arr);  // [ 0, 1, 2, 3 ]
console.log(m);   // [ 0, 1, 4, 9 ]
  • The code above works the same as the code below using .forEach().
const arr = [ 0, 1, 2, 3 ];
const m = [];

arr.forEach( x => {
    m.push(x**2);
  }
);

console.log(arr);  // [ 0, 1, 2, 3 ]
console.log(m);   // [ 0, 1, 4, 9 ]

example 2.

const arr = [ [0,1], [2,3], [4,5] ];
const m = arr.map( x => x[0]**2 + x[1]**2);

console.log(arr);  // [ [0,1], [2,3], [4,5] ]
console.log(m);   // [1, 13, 41]
  • The code above works the same as the code below.
const arr = [ [0,1], [2,3], [4,5] ];
const m = [];

arr.forEach(x => {
  m.push(x[0]**2 + x[1]**2);
});

console.log(arr);  // [ [0,1], [2,3], [4,5] ]
console.log(m);   // [1, 13, 41]

Array.prototype.reduce()

const arr = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;

console.log(arr.reduce(reducer)); // 1 + 2 + 3 + 4 => 10
console.log(arr.reduce(reducer, 5)); // 5 + 1 + 2 + 3 + 4 => 15
const arr = [ [0,1], [2,3], [4,5] ];
const reducer = (accumulator, currentValue) => (
  accumulator + currentValue[0] + currentValue[1]
);

console.log(arr.reduce(reducer, 0)); // 1 + 2 + 3 + 4 + 5 => 15
console.log(arr.reduce(reducer, 5)); // 5 + 1 + 2 + 3 + 4 + 5 => 20

CSS: inheritance

Inheritance

Some property values flow down the document tree (most are not)

Start DOM handling

DOM

  • Document Object Model: Defines how the data of a web page is organized and manipulated.

We can access rewrite the contents or style of DOM by JS.

Change the content of a DOM element

  • index.html
<!DOCTYPE html>
<html>

  <head>
  </head>

  <body>
    <p id='text-area'> Contents will be changed. </p>
    <button id='ok-button'>OK!</button>

    <script src='script.js'></script>
  </body>

</html>
  • script.js
let textArea = document.getElementById('text-area');
let okButton = document.getElementById('ok-button');

okButton.addEventListener('click', function() {
  textArea.innerText = 'changed';
});

Change the style of a DOM element

  • index.html
<!DOCTYPE html>
<html>

  <head>
  </head>

  <body>
    <p id='text-area'> It wil be appeared after click `OK!`. </p>
    <button id='ok-button'>OK!</button>

    <script src='script.js'></script>
  </body>

</html>
  • script.js
let paragraph = document.getElementById('text-area');
let okButton = document.getElementById('ok-button');


paragraph.style.display = 'none';

okButton.addEventListener('click', function() {
  paragraph.style.display = 'block';
  });

객체지향

<객체지향의 사실과 오해>를 읽는 중.

책과 무관하게 일반적으로 객체지향은 4가지 특성으로 설명하곤 한다.

객체지향
어떤?.. 디자인 패턴 책을 읽고 일기장에 적어뒀던 내용.

추상화, Abstraction

객체를 모델링 할 때, 실제 세계를 그대로 가져오지 않는다. 필요한 부분만 가져와서 (feature & behavior) 모델링한다.

캡슐화, Encapsulation

외부에 노출할 인터페이스를 결정하는 것. 객체의 일부분을 private하게 구현.
private이란 객체 안에서만 해당 feature 또는 behavior를 사용할 수 있음을 말한다.
좀 더 규제가 약한 protected는 sub class들까지 어떠한 feature 또는 behavior를 공유하는 것을 말한다.

상속, Inheritance

이미 존재하는 상위 클래스를 가지고 새로운 클래스를 만들 수 있다.
이떄 상위 클래스를 super class, 하위 클래스를 sub class라고 부른다.

다형성, Polymopihsm

subclass에서는 메소드를 오버라이드 할 수 있다.
이를 통해, 각기 다른 객체를 표현할 수 있게 한다
(각기 다른 객체가 아니라, 한 객체 내에서도 다양한 방식으로 특정한 목적을 이룰 수 있게 해준다는 의미에 가깝 않나?)

Number Type

values

The Number type is a double-precision 64-bit binary format IEEE 754 value.
It could have a value of number between -(2^53 -1) and 2^53 -1.
It also contains 3 special symbolic values.

  • +Infinity
  • -Infinity
  • NaN

0

0 is only value that could use in 2 different way. +0 -0

  • +0 === -0 is true.
  • 22 / + 0 is Infinity
  • 22 / - 0 is -Infinity

Framework vs Library

Frameworks

  • Limited flexibility
    • Do things a certain way
    • Hard to deviate
  • Large and full of features
    • Hard to customize
    • Use the whole thing

Libraries

Prototype

Protype은 객체를 생성할 때 활용되는 creational design pattern의 일종.

image

Problem to slove.

어떤 객체의 복사본을 같고 싶을 때 같은 Class의 instance 객체를 새로 생성한 한 후 기존 객체의 필드 값들을 모두 복사해오면 될까요?

다음과 같은 문제 상황을 마주할 수 있습니다.

  1. Private 한 필드는 외부에 노출되지 않아 복사할 수 없다.
  2. 복제본을 생성하려면 객체의 클래스를 알아야 하므로 코드가 해당 클래스에 종속된다. 따라서 추가적인 의존성이 생긴다.
  3. 객체가 따르는 인터페이스만 알고 구체적인 클래스는 알지 못하는 경우가 있다.
    ex)메소드의 매개변수가 일부 인터페이스를 따르는 모든 객체를 허용하는 경우.

image

Solution with Prototype.

image
Protype 패턴은

  • 복제 과정을 (복사를 당하는) 실제 객체에 위임합니다.
  • 모든 객체를 위한 일반적인 인터페이스를 선언합니다.
  • 이때 인터페이스는 객체의 클래스와 커플링이 생기지 않는 방식으로 선언됩니다. 대체로 clone 메소드만 가지고 있도록 구현합니다.
  • clone 을 지원하는 객체를 prototype이라 부릅니다.

만약, 아주 많은 필드들이 다양한 방식으로 설정될 가능성이 있는 경우.
모든 경우에 대해 subclass를 만드는 것 대신 복제를 지원하는 방식을 택할수 있다.

Real World Analogy

image

세포분열이 일어나면, 1개의 세포가 -> 동일한 1쌍의 세포들.
원본 세포가 protype으로서 복사본을 만드는 역할을 했다.

Structure

UML cheat sheet

image

Prototype 기본 구현

image

  1. Prototype 인터페이스는 복제 방법을 선언합니다.
  2. Concrete Prototype 클래스는 복제 방법을 구현합니다. 원본 객체의 데이터를 복제에 복사하는 것 외에도 이 방법은 연결된 객체 복제, 재귀 종속성 풀기 등과 관련된 복제 프로세스의 일부 극단적인 경우를 처리할 수도 있습니다.
  3. 클라이언트는 프로토타입 인터페이스를 따르는 모든 객체의 복사본을 생성할 수 있습니다.

Protytype Registry 구현

image

  • Prototype Registry는 자주 사용하는 프로토타입에 쉽게 접근할 수 있는 방법을 제공합니다.
  • 복사 할 준비가 된 미리 빌드된 개체 집합을 저장합니다.
  • 가장 간단한 프로토타입 레지스트리는 이름 → 프로토타입 해시 맵입니다.
  • 그러나 단순한 이름보다 더 나은 검색 기준이 필요하다면 훨씬 더 강력한 레지스트리 버전을 구축할 수 있습니다.

Pseudo code

Prototype 패턴을 사용하여 클래스에 접근하지 않고도개체의 정확한 복사본을 생성하는예제.

image

모든 Shape 클래스는 clone을 제공하는 동일한 인터페이스를 따릅니다. Shape의 하위 클래스는 자신의 필드 값을 결과 객체에 복사하기 전에 부모의 clone 메서드를 호출할 수 있습니다.

JavaScript: prototype

  • A function's prototype:
    • A function's prototype is the object instance that will become the prototype for all objects created using this functional as a constructor.
  • An object's prototype:
    • An object's prototype is the object instance from which the object is inherited.

React: hook

Hooks

  • functions, let you "hook into" React state and lifecycle feature from function components.
  • hooks don't work inside classes.
  • 2 additional rules:
  • Only call Hooks at the top level. Don't call Hooks inside of loops, conditions, or nested functions.
  • Only call Hooks from React function components. Don't call Hooks from regular JavaScript functions. (Just one other a valid place to call Hooks; custom Hooks)

Stateful Component vs Stateless Component

Stateful Component

  • Components that has a state object
  • like function: data -> ( stateful component ) -> output
  • state를 내부에 가지고 있는 컴포넌트
  • 상위 컴포넌트에서 stateful component를 사용할 때 상태관리를 해줄 필요가 없어서 편리하다. 반면 사용시에 내부 코드를 예측하기 힘들고 확장성이 낮다는 단점이 있다.
  • 다양한 usecase가 존재하지 않으며 오직 한 곳에서만 사용할 컴포넌트라면 stateful하게 작성해도 좋다
  • 또는 무조건 한가지 방식으로 사용되는 컴포넌트라면 오히려 stateful하게 작성하는 것이 효율적일 것

Stateless Component

  • Components that has not a state object
  • like class
  • stateless component의 기능에 필요한 state를 컴포넌트를 사용하는 상위 컴포넌트갖는다
  • 다양한 곳에 적용할 것이며 각 usecase 에 따라 state가 복잡하게 바뀐다면 예측하기 쉽고 확장성이 좋은 stateless방식을 사용하는 편이 좋다

stateful 과 stateless의 장점을 섞어쓰기

  • 명시하지 않아도 특정 state가 적용되지만, 명시하면 명시된 state에 따라 기능이 적용되도록

API mocking tool comparision

msw miragejs
mock Rest API Y Y
mock GraphQL This is the first party Y
runs in browser or node in browser ( also in node but only browser like environment )
to intercept network requests uses a Service Worker ( so reqs are shown in the Network tab in DevTools) uses Pretender.js
set up need to generate a Service Worker file in the public dir only import it on FE code

HTTP vs SOCKET

서버에서 클라이언트로 데이터를 가져오기 위한 통신 방법들.

HTTP 통신

  • 클라이언트의 요청(Request)가 있을 때만 서버가 응답(Respond) 한다.
  • 해당 정보를 전송하고 곧바로 연결을 종료한다. (단방향 통신)
  • 콘텐츠 위주의 데이터를 사용할 때 유용한다.

Socket 통신

  • 서버와 클라이언트가 특정 port를 통햇 실시간으로 양방향 통신을 한다.
  • http애서 클라이언트만 요청(Request) 보낼 수 있는 것과 달리, Socket 통신에서는 서버 역시 클라이언트로 요청(Request)을 보낼 수 있다.
  • 계속 연결을 유지하는 연결 지향형 통신이므로, 실시간 통신이 필요한 경우 자주 사용한다.
  • 즉각적인 양방향 정보 교환이 필요할 경우 유용한다. 실시간 스트리밍을 통한 중계, 온라인 게임 등.
  • 실시간 동영상 스트리밍을 서비스를 http 통신으로 구현한다면, 동영상이 시작됐을 때 부터 종료될 때까지 계속 클라이언트 측에서 서버로 요청을 보낼 것이다. -> 서버 과부하

React: setState

Problem

동시에 이벤트에서 각각 state를 업데이트 하는 경우 값이 누락되는 현상.

How to solve

setState() 의 this.state 업데이트 방식

우선 setState는 항상 state를 비동기적으로 업데이트 한다는 점을 알고있으면 도움이 될 것 같습니다.

  • setState는 항상 비동기적으로 수행됨.
  • setState를 호출했다고 해서 바로 this.state에 새로운 값이 반영될 것이라고 기대해서는 안 됨.
  • setState를 호출했을 때 this.state를 업데이트 하려는 요청을 보낸 것이라고 이해하는 편이 더 적합함.

Update by value VS Update by updater function

이런 특성 때문에 앞서 전달드린 문제가 발생할 수 있습니다.

  • setState에 newValue를 인자로 주어 업데이트하는 경우, 현재 렌더되어있는 this.state를 기준으로 새로운 값을 연산합니다. 따라서 같은 렌더링 주기 내에서 setState를 여러번 호출하면 직전 값을 덮어씌워버립니다. (more)
  • 이러한 현상을 방지하기 위해서는 setState에 updater 함수를 전달하여 this.state 값을 업데이트 해주면 됩니다. 그러면 현재 렌더되어있는 this.state값이 아니라 직전 state 값에 접근하여 연산할 수 있게 됩니다. (more)

Conclusion

  • required 🔥: 아래 나열한 3가지 조건에 해당될 때에는 의도한대로 state가 업데이트되지 않을 것 입니다. setState의 인자로 updater를 전달해주는 방식으로 fix 할 수 있습니다.
    1. 한 렌더링 주기에 setState를 여러번 호출하면서,
    2. newValue를 인자로 state를 업데이트 하고,
    3. 이전 state값을 기반으로 다음 state를 연산을 해야하는 경우 문제가 됩니다.
  • optional 😲: 이전 state 값을 기반으로 다음 state 연산을 계산하게 되는 경우에, setState의 인자로 무조건 updater 함수를 준다면 이런 케이스를 미연에 방지할 수 있을 것 같습니다. 앞으로 컨벤션을 이렇게 가져가는게 좋을까요?

Reference

THE NEW FRONT-END STACK: JS, APIS, MARKUP

The New Stack == The JAM Stack

  • The stack has moved up a level.
  • JavaScript, APIs, and MarkUP.

JavaScript

  • Any dynamic programming during the request/response cycle handled by JavaScript, running entirely on the client.
  • This could be any frontend framework, library, or even vanilla JavaScript.

APIs

  • All server-side processes or database actions are abstracted into reusable APIs, accessed over HTTP with JavaScript.
  • These can be custom-built or leverage third-party services.

MarkUp

  • Templated markup should be prebuilt at deploy time, usually using a site generator for content sites, or a build tool for web apps.

Reference

  • THE NEW FRONT-END STACK by @bilmann on JamStack
  • Rise of the JAMstack by @MathiasBiillman on JamStack
  • JamStack References go

REST API

정의

  • REpresentation State Transfer
  • REST 하게 클라이언트랑 서버간의 데이터를 주고 받는 것.
  • 자원의 표현(이름)으로 구분하여 해당 자원의 상태(정보)를 주고 받는 것.
  • 자원(Resource)의 표현(Representation)에 의한 상태(State) 전달.
    • 자원: 해당 소프트웨어가 관리하는 모든 것. 문서, 그림, 데이터, 해당 소프트웨어 그 자체 등.
    • 자원의 표현: 그 자원을 표현하기 위한 이름. 데이터베이스의 학생 정보가 자원일 때, student를 자원의 표현으로 정하는 등.
    • 상태 전달: 데이터가 요청되는 시점에 자원의 상태를 전달한다. JSON 혹은 XML을 통해 데이터를 주고 받는 것이 일반적.
  • WWW과 같은 분산 하이퍼미디어 시스템을 위한 소프트웨어 개발 아키텍처의 한 형식.
    • 기본적으로 웹의 기존 기술과 HTTP 프로토콜을 그대로 활용한다.
    • 네트워크 상에서 클라이언트와 서버 사이의 통신 방식 중 하나.

구성

  • 자원(Resource)
  • 행위(Verb)
  • 표현(Representation)

특징

  • Uniform Interface: URL로 지정한 리소스에 대한 조작을 통일되고 한정적인 인터페이스로 수행하는 아키텍처 스타일.
  • Stateless: 무상태적 성격을 갖음. == 작업을 위한 상태 정보를 따로 저장/관리 하지 않는다.
  • Cacheable: HTTP라는 웹 표준을 그대로 사용하므로, 웹에서 사용하는 기존 인프라 또한 그대로 활용 가능.
  • Self-descriptiveness: REST API 메시지만 보고도 쉽게 이해할 수 있는 표현 구조.
  • Client-Server 구조: REST 서버는 API 제공. Client는 사용자 인증이나 컨텍스트(세션, 로그인 정보)
  • 계층형구조

REST API 디자인 가이드

  • URL을 통해 자원을 명시.
  • 자원에 대한 행위는 HTTP Method를 통해 CRUD operation을 적용.
    • POST -> Create
    • GET -> Read
    • PUT -> Update
    • DELETE -> Delete
    • PATCH

장점

  • HTTP 프로토콜의 인프라를 그대로 사용하므로 REST API 사용을 위한 별도의 인프라를 구축할 필요가 없다.
  • HTTP 프로토콜의 표준을 최대한 활용하므로 웹의 장점을 가져갈 수 있게 해준다.
  • HTTP 표준 프로코콜을 따르는 모든 플랫폼에서 사용할 수 있다.
  • Hypermedia API의 기본을 충실히 지키면서 범용성을 보장한다.
  • REST API 메세지가 의도하는 바를 명확히 나타내므로 의존하는 바를 쉽게 파악할 수 있다.
  • 여러가지 서비스 디자인에서 생길 수 있는 문제를 최소화한다.
  • 서버와 클라이언트의 역할을 명확히 분리한다.

단점

  • 표준이 존재하지 않는다.
  • 사용할 수 있는 메소드가 4가지 밖에 없다. (HTTP Method 형태를 따르므로 제한적)
  • 구형 브라우저가 지원하지 못하는 부분이 존재한다.
    • PUT, DELETE 사용불가
    • pushState 지원불가.

Typescript

TypeScript 란?

  • JavaScript and More+
    • 자바스크립트에 '타입'이라는 추가 구문을 제공. IDE와 통합되어 개발시 오류 캐치 등 개발 생산성에 도움이 됨. (브라우저, node.js, Deno)
  • A Result You Can Trust
    • 어차피 JavaScript로 변환되므로, 이미 JS가 지원되는 모든 곳에서 실행 가능.
  • Safety at Scale
    • TypeScript는 JavaScript를 이해합니다.
    • 타입 추론을 제공합니다.
  • (old 캐치프라이즈) TypeScript는 JavaScript의 Super Set 이다.
  • (new 캐치프라이즈) TypeScript is JavaScipt with syntax for types. 타입스크립트는 타입 구문을 가지는 자바스크립트.
    • 이제는 prososal 단계의 ES syntax를 포함하고 있어서.

w/ 객체지향프로그래밍, OOP.

사물 또는 사람을 데이터로 표현한다면? 그리고 그 데이터가 코드라면?

const cat = {
    name: '먼지',
    age: 10,
    face: '납짝',
    makeSound: () => {
        alert('이야옹')
    }
}

TypeScript와 함께라면 데이터를 (손쉽게) 추상화 해서 메타데이터를 만들 수 있음.

Cat 데이터 설명서 ->

interface Cat {
    name: string
    age: number
    face: string
    makeSound: function
}

우당탕탕 테스트코드 작성기

Motivation

  • Nextjs 기반의 프로젝트 진행중.
  • 리팩터링 할 때 특히 테스트 코드가 있으면 개발 속도에 긍정적인 영향. 또 신뢰도가 높아짐.
  • 테스트를 작성하기로 함.
  • 또 사내에서 이미 사용중인 codecov CI를 연동해 코드 커버리지를 지속적으로 체크하기로 함.

How

  • UI 테스트는 변경이 많은 부분이니 최소화하는 것이 좋음.
  • 비즈니스 로직, 또는 어플리케이션 로직에 가까운 부분부터 테스트 해보고자 함.
  • CRUD기능을 위한 API endpoint를 작성해뒀음. 각 endpoint에서 data가 오갈 때 validate하고 적절한 데이터라고 판단되면 case convention을 바꾸어 반환해주는 메소드를 작성한 바 있음. 이 함수에 대해 test를 했음. 우선 올바른 데이터가 주어졌을때, 적절한 리턴값을 주는지 체크하는 테스트를 짬.
  • jest라는 자바스크립트 테스트 프레임워크를 사용하기로 했음. All-in-one으로 Test Runner, Test Matcher나 Test Mock 역할을 모두 해주므로 셋업할 때 공수가 덜 들어가며, 커뮤니티고 크다. 아직 테스팅에 익숙하지 않기때문에 이런 점들이 장점으로 다가왔다. 추후에 UI 테스트를 위해 React Test library를 사용 할 때도 jest 위에 얹으면 간단하게 configuration을 끝낼 수 있다.
  • 브라우저단의 유저플로우를 Datadog의 synthetic monitoring 을 셋업해서 job이 돌아가며 체크하도록 했다.

To-do

  • UI 테스트를 잘 하기 위해서는? (테스트 할 바운더리 정하기, UI 테스트 시작하기, ... , 등등)

Reference

  • 코드 커버리지 CI codecov.io
  • 자바스크립트 테스팅 프레임워크 jest
  • React Testing Library

DataTypes in JavaScript

image

Primitive Type

-A variable that stores a primitive value is accessed by value

  • Primitive is data that is not an object and has no methods
  • Symbol is new in ES2015
TypeName value
Number only a double-precision 64-bit binary format IEEE 754 value
String a set of "elements" of 16-bit unsigned integer values
Boolean only true or false
Symbol a value symbol id token that serve as unique ID
null a value null represents intentional absence of any object value
undefined A variable that has not been assigned a value

Reference Type

  • A variable that stores an object accessed by reference
TypeName
Object
  • Special Type of Object
TypeName
Function
Array
Date
RegExp

CSS layout

  • 임의의 변화를 주기 전은 normal flow 에 따라 레이아웃이 결정된다
  • display 속성의 값에 따라 레이아웃이 달라진다
  • Flex box 은 일차원 레이아웃(row나 column)에 아이템들을 배치할 때 사용한다.
  • Grids row와 column에 따라 아이템을 배치할 수 있도록 돕는 레이아웃 시스템이다.
  • float text blocks 사이에서 image를 floating시키는 등에 사용할 수 있다.
  • position 하나의 원소를 normal document layout flow에서 빼내 올 수 있도록 해주는 속성이다.

reference

CSR vs SSR

1. CSR(Client-side Rendering)이란 무엇이며, 그것의 장단점에 대하여 설명해주세요.

  • 홈페이지 첫 랜딩에서 가져온 자원 HTML, CSS, JS을 가져옵니다. 해당 자원들을 토대로 JS를통해 DOM을 추가적으로 조작해서 페이지를 만듭니다. 그 이후 path별로 다시 자원을 가져오는 것이 아니라, 페이지를 이동하는 것처럼 DOM을 새로 조작하여 다른 뷰를 보여줍니다.
  • 클라이언트 단에서 DOM에 접근하여 새로운 HTML 구조를 만들기 때문에. 기존 방식대로 페이지 별로 이미 만들어진 HTML 을 통짜로 받는 것보다, 좀 더 앱과 같은 자연스러운 사용자 경험을 전달 할 수 있습니다.

2. SPA(Single Page Application)로 구성된 웹 앱에서 SSR(Server-side Rendering)이 필요한 이유에 대하여 설명해주세요.

  • SSR에 비해서 CSR은 페이지 첫 로딩 속도가 늦어질 수 있다. 그리고 검색 크롤러 봇이 페이지에 등록했을 때 CSR로 구성되어있는 SPA는 빈 페이지를 보여줄 것이므로 검색 엔진에 잘 반영되지 않는다. (react-helmet 등 어느정도 보완할 방법이 있다.)
  • 따라서 만들고자하는 웹페이지의 특성과 필요에 따라 CSR, SSR 좀 더 적합한 방법을 선택하여 사용하면 된다.

3. Next.js 프로젝트를 세팅한 뒤 yarn start 스크립트를 실행했을 때 실행되는 코드를 nextjs github 레포지토리에서 찾은 뒤, 해당 파일에 대한 간단한 설명을 첨부해주세요.

터미널에 yarn start을 입력하면 다음과 같은 안내 문구와 함께 포트 3000 에 로컬 서버가 시작됩니다.

터미널

> yarn start

yarn run v1.22.19
$ next start
ready - started server on 0.0.0.0:3000, url: http://localhost:3000

yarn start 는 nextjs의 cli 명령어인 next start 를 실행합니다. package.json은 npm 프로젝트의 세부 사항을 핸들링 할 수 있는 파일인데요. 그런 로컬 프로젝트의 package.json 에 스크립트 명령어로 "start": "next start" 라고 명시해두었기 때문입니다.

로컬 프로젝트 package.json

{
...
{
  "scripts": {
    ...
    "start": "next start",
    ...
  },
  ...
}

이제 next start라는 cli 명령어가 실행될 때, 실행되는 코드를 nextjs 레포지토리에서 소스코드에 찾아보려고 합니다.

프로젝트 최상위에 존재하는 package.json을 보면 "workspaces""packages/*" 으로 설정되어있는 것을 확인할 수 있습니다.
이는 packages/ 폴더 하위에는 또다른 유효한 packages.json 파일이 존재한다면, packages/ 폴더 하위가 workspace로 인식될 것이라는 뜻 입니다. 의미를 정확하게 이해한 것 같진 않지만, 대략적으로 packages/ 폴더 하위 부분이 nextjs 패키지 동작에 핵심적인 소스 코드들이 위치하고 있는 것으로 이해했습니다.

packages/ 폴더 하위에는 create-next-app, next 등등 여러 폴더가 위치하고 있고, 각각의 폴더는 고유한 packages.json을 가지고 있습니다. 각 폴더가 하나의 workspace로 인식되는 것으로 보입니다.

최상위 packages.json에서 next라는 명령어의 path가 packages/next/...로 설정되어 있는 만큼, next 파일 하위를 살피면 될 것 같습니다.

"scripts": {
  ...
  "next": "node --trace-deprecation --enable-source-maps packages/next/dist/bin/next",
   ...
}

next/package.json 에는 실행 가능한 패키지를 만들기 위한 설정값인 "bin"이 있는데, 다음과 같이 설정되어 있습니다.

"next": "./dist/bin/next"

next 라는 이름으로 "./dist/bin/next" 위치의 파일을 실행시킨다는 의미입니다. next/ 폴더 하위에는 dist/ 폴더는 없으나, bin/next 파일이 존재하고 있습니다. (path에 dist가 끼어들게 된 경위는 일단 건너뛰려고 합니다.)

bin/next 파일을 보면 우선 디펜던시인 react, react-dom의 패키지를 무사히 불러올 수 있는지 확인하고 cli 명령어로 들어온 키워드에 따라 다른 동작을 실행시킵니다.

예를들어, yarn next --version 명령어를 실행시킨다면, 다음의 코드가 동작하여 Next.js v12.3.1 과 같은 문자열을 터미널에 보여줍니다. 키워드가 --version 인 경우, 여기서 버전 문자열 출력 후 프로그램을 종료하는 것을 확인할 수 있습니다.

if (args['--version']) {
  console.log(`Next.js v${process.env.__NEXT_VERSION}`)
  process.exit(0)
}

bin/next에서는 키워드가 예약된 명령어로 존재하는지를 확인 하기 위해 commands 모듈을 활용 합니다.

import { commands } from '../lib/commands'
...

// Check if we are running `next <subcommand>` or `next`
const foundCommand = Boolean(commands[args._[0]])

lib/commands 모듈은 각 명령어 키워드를 key로 이를 실행하기 위한 콜백함수를 value로 갖고 있는 객체를 export 합니다. 키워드 "start"는 ../cli/next-start 모듈에서 nextStart를 반환하는 콜백함수를 value로 갖고 있습니다. 따라서 Boolean(commands["start"])true 입니다.

export const commands: { [command: string]: () => Promise<cliCommand> } = {
  build: () => Promise.resolve(require('../cli/next-build').nextBuild),
  start: () => Promise.resolve(require('../cli/next-start').nextStart),
  export: () => Promise.resolve(require('../cli/next-export').nextExport),
  dev: () => Promise.resolve(require('../cli/next-dev').nextDev),
  lint: () => Promise.resolve(require('../cli/next-lint').nextLint),
  telemetry: () =>
    Promise.resolve(require('../cli/next-telemetry').nextTelemetry),
  info: () => Promise.resolve(require('../cli/next-info').nextInfo),
}

다시 bin/next를 보면, 실행가능한 명령어가 존재하는 경우 import 해온 콜백함수를 실행시키는 것을 확인할 수 있습니다.
'build'의 경우 실행 이후 프로그램을 종료하고, 'start'등 다른 키워드의 경우 실행시킨 후 프로그램을 계속 살려두는 것을 확인할 수 있습니다.

const command = foundCommand ? args._[0] : defaultCommand

...

commands[command]()
  .then((exec) => exec(forwardedArgs))
  .then(() => {
    if (command === 'build') {
      // ensure process exits after build completes so open handles/connections
      // don't cause process to hang
      process.exit(0)
    }
  })

lib/commands 모듈에서 확인했듯이, next start 명령어의 경우 cli/next-start의 nextStart를 가져옵니다. nextStart는 다음과 같습니다. 별다른 argv를 전달하지 않았다면 host는 0.0.0.0으로 port는 3000번으로 설정하여 startServer 모듈을 이용해서 서버를 실행시킵니다. 그리고 성공했다면, 처음에 로컬 프로젝트에서 yarn start를 했을 때 본 문자열인 started server on ${host}:${app.port}, url: ${appUrl}를 출력합니다. 만약 error가 발생했다면 error log를 출력합니다.

import { startServer } from '../server/lib/start-server'
...,
const nextStart: cliCommand = (argv) => {
...,
 let port: number =
    args['--port'] || (process.env.PORT && parseInt(process.env.PORT)) || 3000
  const host = args['--hostname'] || '0.0.0.0'
  ...,
  startServer({
    dir,
    hostname: host,
    port,
    keepAliveTimeout,
  })
    .then(async (app) => {
      const appUrl = `http://${app.hostname}:${app.port}`
      Log.ready(`started server on ${host}:${app.port}, url: ${appUrl}`)
      await app.prepare()
    })
    .catch((err) => {
      console.error(err)
      process.exit(1)
    })
}
...

/server/lib/start-server 파일의 startServer는 다음과 같습니다. http 모듈을 활용해서 서버를 만들고 next app을 서버가 listening 하도록 합니다.
사용된 모듈은 http-proxy로 보입니다. next workplace의 package.json이 가지고 있는 http 관련 의존성이 http-proxy와 http-browserify인데, http-proxy 쪽이 createServer, server.on 등의 메소드를 제공하고 있기 때문입니다.

import http from 'http'
...
export function startServer(opts: StartServerOptions) {
  let requestHandler: RequestHandler

  const server = http.createServer((req, res) => {
    return requestHandler(req, res)
  })
  ...,

  return new Promise<NextServer>((resolve, reject) => {
    
    ...,

    server.on('listening', () => {
      const addr = server.address()
      const hostname =
        !opts.hostname || opts.hostname === '0.0.0.0'
          ? 'localhost'
          : opts.hostname

      const app = next({
        ...opts,
        hostname,
        customServer: false,
        httpServer: server,
        port: addr && typeof addr === 'object' ? addr.port : port,
      })

      requestHandler = app.getRequestHandler()
      resolve(app)
    })

    server.listen(port, opts.hostname)
  })
}

Testing for UI

Testing for UI

React UI Testing 을 번역

테스트를 하는 이유

  • 버그 찾기
  • 새로운 커밋에 문제가 없는 것을 확실히 하기 위해
  • 테스트를 living documentations으로 남겨두기 위해

1. Structural Testing

  • UI의 구조와 어떻게 배치하는지 에 대해 중점을 둔 테스트
    image
  • structural testing에서는 다음과 같은 컨텐츠를 테스트:
    • "Lof in to Facebook"이라는 타이틀
    • username과 passward를 받을 두개의 input
    • submit button
    • 에러가 있을 때 보여줄 에러화면
  • React에서 structural testing을 하는 방법으로 enzyme 을 사용 할 수도 있지만 Jest’s snapshot testing을 사용하는게 더 간단.

2. Interaction Testing

  • button, link, input 등 많은 UI요소들을 통해 사용자와 상호작용을 수행.
  • 이처럼 UI는 사용자와 상호작용하기위한 것이므로 상호작용테스트는 중요하다.
  • interaction testing의 테스트 컨텐츠 예:
    • submit button을 눌렀을 떄 username과 passward를 전달하는지
    • "Forgotten Account" 링크를 눌렀을 때 새로운 페이지로 리디액트되는지
  • React에서 interaction test 하는 간단한 방법은 enzyme 을 사용하는 것.

3. CSS/Style Testing

  • 스타일 테스트에서는 변경된 코드 사이에 UI 구성요소의 모양과 느낌을 평가한다.
  • 보통 이미지를 비교해서 수행한다.
  • 만약 inline styles를 사용한다면 JEST snapshot으로 테스트할 수 있지만, 그렇지 않다면 BackstopJS Gemini Happo 을 사용하는걸 고려해보는게 좋다.

Tools

  • React Testing Library
    • 각각의 컴포넌트 내부보다 렌더링된 화면 결과물에 대한 테스팅 위주. 특정 이벤트 이후 원하는 변화가 화면에 일어났는지 등.
  • enzyme
    • Enzyme is a JavaScript Testing utility for React that makes it easier to test your React Components' output.
    • Focused on interaction testing. Simulate user inputs.
    • 각각의 컴포넌트 내부를 점검하는데 초점. props와 state를 확인하고 내장 메소드를 직접 호출하는 등.
    • Test inside storybook(doc) using storybook-addon-specifications
  • jest

Monorepo

Mono-repo

lovely-side

  • Out-of-the-box Android
  • Single source of truth
    • Coding style
    • Architectural patterns
    • Testing practices
  • Simple code sharing

dark-side

  • IDE lag
  • Git slowdown
  • Broken master
  • Long build times

Multi-repo

lovely-side

  • Strong ownership
  • Fast build times
  • Separate git repos
  • Isolated master breakage

dark-side

  • Overhead
  • Need a big codebase
  • Silos
    • Code style
    • Architectural patterns
    • Testing practices
  • Functionality duplication
  • Dependency hell

Back again Mono-repo

  • IDE lag -> intelliJ
    • -> Mercurial
  • Git slowdown
    • -> Submit queue: make sure that you are not braking test
  • Broken master
    • -> Buck: Build only just section of code that you worked on
  • Long build times

reference

JavaScript: scope and variables

var

var in Function Scope

function sum(a, b) {
  // Function Scope
  var result = a + b;
}
sum(2, 2);
console.log(result); // VM431:1 Uncaught ReferenceError: result is not defined

var is function scope, so can not access to variable result at outside of function.

var in Block Scope

for (var i=0; i<10; i++) {
  // Block Scope
}
console.log(i) // 10

var is function scope, so can access to variable i at outside of block.

Web Animations

performance of animations

  • 애니메이션 만들 떄 60fps 유지하기. (사용자가 인지하기에 자연스러운 프레임 수)
  • 페이지의 기하학적 형태 (layout) 변경이나 painting를 유발하는 애니메이션 속성은 특히 비용이 많이 듬
  • 최대한 transformsopacity 변경 애니메이션만 사용하기
  • 어떤 이벤트로 인해 200ms 이내에 애니메이션이 트리거될 수 있는 경우 will-change 를 사용해서 브라우저가 스스로 애니메이션을 계획할 수 있도록 하기

CSS versus JavaScript

  • CSS 기반 애니메이션과 기본 지원되는 웹 애니메이션은 일반적으로 compositor thread라고 불리는 스레드에서 처리된다. 스타일 지정, 레이아웃, 페인트 및 자바스크립트가 실행되는 브라우저의 main thread는 이와 다르다. 즉, 브라우저가 main thread에서 비용이 많이 드는 작업을 실행 중인 경우에도 compositor thread의 애니메이션들은 방해받지 않고 계속 실행된다.
  • 애니메이션이 paintlayout을 트리거하는 경우, CSS든 JS든 작업을 수행하기 위해 main thread가 필요하다. 따라서 paintlayout의 오버헤드는 CSS 또는 JS 실행과 연관된 모든 작업에 악영향을 미친다.
USE CSS USE JS
상대적으로 작고 스스로의 state가 포함된 UI 요소의 애니메이션의 경우 CSS를 사용 애니메이션을 세밀하게 제어해야 하는 경우 JS를 사용
CSS transitions & animations 은 side menu나 tooltip같은데 사용하면 좋다. 애니메이션 자체는 CSS에서 동작하게하면서 상태관리는 JS로 하는 것도 가능. Web Animations API는 modern browser들의 표준적인 접근법. JS는 stop, pause, slow down, reverse the animations 이 필요할 때 유용.
  • 만약 이미 애니메이션 기능이 있는 jQuery's .animate()GreenSock's TweenMax 자바스크립트 프레임워크가 익숙하다면 그것을 사용하는게 효과적.

reference

  • web fundementals - animations (link)

SSR CSR

(발표자료)
발표했던 내용을 복기할 겸 글로 정리해보려고 함.

사용되는 용어

흠..

  • SPA: Single Page Application

렌더링 방법

  • SSR: Sever Side Rendering
  • CSR: Client Side Rendering

성능

  • TTFB: Time To First Byte
  • FP: First Paint
  • FCP: First Contentful Paint
  • TTI: Time To Interaction

SPA?

  • Single Page Application 한 페이지에 여러 페이지를 표현하는 것을 말함.
  • 전통적인 페이지 렌더링 방식인 Static Rendering의 경우, Client가 페이지를 요청하면 Server에서 렌더할 준비가 완료된 HTML 파일을 내려주는 것. 따라서 페이지 전환 또는 새로운 데이터 fetching에 따라서 깜빡거린다던가, UX가 제한적 이였음.
  • SPA 등장 배경:
    • Ajax가 나온 이후에는 데이터를 seamless하게 fetching 할 수 있게 됨.
    • Webpack과 같은 모듈 번들러의 등장. 덕분에 HTML, CSS, JS 파일들을(?) 번들링하여 하나의 렌더 가능한 하나의 HTML, JS 파일로 만들 수 있음. (보충 필요)
    • 클라이언트 기기들의 발전. SPA를 만들기위한 연산을 각 클라이언트 기기들이 감당할 수 있게 됨.

Ajax?

  • Asynchronous javascript and xml: 이름 그대로 풀이하자면 비동기적인 자바스크립트와 xml 이란 뜻. 여기서 xml은 무시해도 된다. 왜냐하면 Ajax로 처리할 수 있는 데이터가 xml 뿐 아니라 csv, json 등의 타입도 해당하기 때문이다.
  • Ajax는 웹 어플리케이션이 Static Rendering만 지원하던 시절, 네이티브 앱처럼 풍부한 UX를 지원하기 위해 제안된 (기존 기술에 대한) 새로운 접근법이였다.
    • XHTML, CSS로 기존 방식대로 화면을 presentation 함.
    • DOM을 이용해 다이나믹한 화면과 인터랙션을 보여줌.
    • XML, XSLT를 통한 데이터 교환 및 조작.
    • XMLHttpRequest를 통해 비동기적으로 데이터를 retrival 한다.
    • JS로 이 모든 것을 바인딩 함.

CSR

  • 브라우저 렌더링에 필요한 모든 일을 다 할 것 ~~
    • All logic, data fetching, templating, routing ...

CSR에게 TTFB란?

  • Time To First Byte를 확인하는 것은 의미 없다.
  • 왜냐하면 가장 처음으로 렌더하는 것은 빈 화면이기 때문이다.
  • html 파일을 보면 바디에
    만 달랑 들어가 있을 것이고, 그 당시 브라우저 창 내의 스크린인 비어있을 것이다.

CSR에서 TTI와 FCP는?

  • Time To Interaction >>> First Contentful Paint
  • 사용자가 처음으로 주어진 화면과 인터랙션 할 수 있는 시간이 빨라진다.
  • 이에 비해 Content를 클라이언트에서 하나하나 받아와야하기때문에 FCP는 상대적으로 저하될 수 있다.

CSR을 사용할 경우 SEO에 대한 영향

  • 검색엔진 크롤링 봇이 페이지를 방문하면서, 검색 키워드와 연관되어있는 양질의 컨텐츠인지 확인하는데. 사람이 아니라 로봇이기때문에 방문 시간이 아주 짧다. 그래서 봇은 CSR을 이용해 렌더링한 페이지를 방문했을 때 빈 화면을 보게된다. -> SEO에 안 좋은 영향.
  • react-helmet등의 라이브러리를 활용하여 HTML head에 속성값을 넣어주는 등의 방법으로 보완할 수 있다.

SSR

  • Static Rendering과 같이 서버에서 준비된 HTML 파일을 내려준다.
  • SPA로 작성하더라도 웹서버에서 번들링을 완료하여 바로 render 엔진이 사용할 수 있는 형태로, 클라이언트 기기에 내려주는 것이다.

SSR의 단점

  • Static Rendering과 마찬가지로 flickering 이슈가 있다.
    -Time To First Byte 성능이 상대적으로 저하. 웹서버에서 렌더링에 필요한 작업을 수행한 뒤 내려주기 때문. -> 만약 획일적인 페이지를 서빙할 경우 SSG를 활용하면 됨.

CSR to SSR

image

reference

Asynchronous Programming

INDEX

  • Async Patterns
    • Parallel vs. Async
    • Callbacks, one of fundamental unit of Asynchronous Programming
    • Thunks
    • Promises
    • Generators / Coroutines
    • Event Reactive (observables)
    • CSP (channel-oriented concurrency)

CSS: selectors

CSS Syntax Selectors

how to select elements from HTML file in CSS

  • Select all of elements that have h1 HTML tag
h1 {
  color: blue;
}
  • Select all elements that have a class set to btn--blue
.btn--blue {
  color: blue;
}
  • Select an element that has an id set to entry-textarea
#entry-textarea {
  border: 2px solid #ccc;
}
  • Select all p elements that have a div element as parent
div p {
  text-align: center;
}
  • Select multiple elements
h1, h2, p {
  color: blue;
}

JS prototype

정의

자바스크립트에서 프로토타입이란 객체에 프로퍼티를 정의하고, 객체 인스턴트에 자동으로 적용되게 해주는 함수의 기능.

reference

  • js 닌자 책

CSS: priority

CSS is called Cascading Style Sheets. because properties are applied in a specific order based on priority.

  • CSS Priority
    • html tag < class < id < !important
  • 특정 element가 여러 selector들에게 선택받고 있을 때, 더 강한 priority를 갖은 selector에서 다른 곳에서 이미 정의된 property를 overwrite 했다면, 더 강한 priority의 속성값을 따라간다.

Composite

Structural Design Pattern

Structural Design Pattern들은 객체와 클래스들을 더 큰 구조로 (그 구조의 유연성과 효율성을 해치지 않으며) 조합하는 방법을 소개합니다.

Composite

image
Composite 패턴은 Structural Design Pattern의 일종으로, 객체(object)들을 트리(tree)구조로 구성(compose)하게 해줍니다. 그리고 트리 구조들이 각각 개별 객체인 것으로 취급하며 작업할 수 있습니다.

Real-world Analogy

Composite 패턴은 객체들을 트리 구조로 구성하는 패턴입니다. 따라서 패턴을 적용하고자하는 어플리케이션의 코어 모델이 트리 형태로 나타낼 수 있어야 의미가 있습니다.

트리로 표현 할 수 있는 모델의 예는 군대가 있습니다.
image
거의 모든 나라의 군대는 위계로 이루어져 있습니다. 군사령부는 군단으로 이루어져있고, 군단은 사단으로 이루어져있고, ..., 소대에는 전투원들이 소속되어 있습니다.

  • 이때 군사령부, ..., 소대, 전투원은 각각 트리의 원소라고 볼 수 있습니다.
  • 특히 전투원은 말단 원소인 leaf element라고 볼 수 있습니다.
  • 계층적 포함관계를 edge 를 통해 나타냅니다.

Problem to solve

목표

주어진 클래스 ProductBox를 이용하여 주문시스템 Order를 만들고자 합니다. 하나의 Order의 총 가격은 어떻게 구할 수 있을까요?

세부사항

image

  • Box는 여러 Product을 가질 수 있습니다. (갖지 않을 수도 있다)
  • Box는 크기가 더 작은 Box들을 가질 수 있습니다. (갖지 않을 수도 있다)
  • 더 작은 Box 또한 여러 Product과 좀 더 작은 Box를 가질 수 있습니다. 좀 더 작은 Box 또한 마찬가지입니다.
  • Order는 두 가지 타입의 객체를 가질 수 있다. 포장되지 않은 상품들을 나타내는 Product 타입, 그리고 포장된 상품을 나타내는 Box 타입이 있다.

문제상황

모든 포장을 풀고 각 Product의 가격을 확인한다면 Order의 총 가격을 구할 수 있습니다. 이 직관적인 접근은 Real-world에서 충분히 실행 가능한 방법이기는 하나, Program 상에서 구현하기에는 어려움이 있습니다.

ProductBox의 구체적인 클래스를 알아야만하고, 모든 중첩된 레벨, 또 지저분한 세부사항까지 모두 알아야만 하기 때문입니다. 이를 구현하는 것은 어색하게 느껴집니다. 또한 구현이 아예 불가능 할 수도 있습니다.

Solution with composite

우선 ProductBox의 공통적인 인터페이스를 만듭니다. 주문 프로그램의 목표는 총 가격을 알아내는 것이었으니, 총 가격을 계산하는 메소드가 정의된 인터페이스라면 적당할 것 같습니다.

총 가격을 계산하는 메소드를 totalPrice()라고 부르겠습니다. totalPrice()은 다음과 같이 동작합니다.

  • ProducttotalPrice()는 단순히 상품의 가격을 반환하도록 정의합니다.
  • BoxtotalPrice()는 박스에 속한 모든 아이템을 순회하며 가격을 조회하고 모두 합해 반환하도록 구현합니다.
  • Box의 아이템이 더 작은 Box인 경우, (같은 로직을 가지고 있는) 더 작은 BoxtotalPrice()가 실행됩니다. 이는 가장 안 쪽의 component의 가격이 계산될 때까지 재귀적으로 반복됩니다.
  • BoxtotalPrice()에 패키징 가격을 덧붙이는 등 추가 로직을 포함시킬 수도 있습니다.

Composite 패턴을 활용한 접근법의 가장 큰 장점은 트리를 구성하고 있는 객체의 구체적인 클래스를 신경쓰지 않아도 된다는 점 입니다. 객체가 단순한 상품인지 또는 포장된 박스인지의 차이 또한 신경쓰지 않아도 됩니다. 공통 인터페이스를 통해 객체를 동일한 방식으로 다룰 수 있기 때문입니다.

Structure

image

객체

  • Component 인터페이스는 simple element와 complex element 모두에 해당하는 공통 operation들을 묘사합니다.
  • Leaf는 하위 요소(sub-element)가 없는 트리의의 기본 element입니다. 대게, leaf compoent들은 대부분의 실제 작업을 하게 됩니다. 왜냐하면 그 작업을 더 이상 위임 할 곳이 없기 때문입니다.
  • Container (a.k.a. composite)는 하위 요소가 있는 elements입니다. Container는 자식 요소의 구체적인 클래스들을 모릅니다 component interface를 통해서만 모든 하위 요소와 함께 동작합니다.
    Container는 요청을 받으면 하위 요소에 위임합니다. 그 후 결과를 처리하는 과정을 거친 뒤, 최종 결과를 client에게 반환합니다.
  • Client는 어떤 element에 접근할 때, 항상 component interface를 통해 접근합니다. 따라서 client는 트리의 simple element인지 complex element인지 관계없이 같은 방식으로 작업할 수 있습니다.

관계

  • Client는 Component interface에 대해 association 관계를 갖습니다. Client는 Component interface를 통해 소통한다는 의미입니다.
  • Leaf와 Composite 클래스는 Component interface를 implementation 합니다. Component interface에 선언되어있는 메소드들을 정의한다는 의미입니다.
  • 또한 Composite 클래스는 Component interface를 aggregation하고 있습니다. Component interface를 직접 가지고 있다는 의미입니다.

Pseudo code

Composite 패턴으로 Graphical Editor에서 기하 도형 쌓기 기능 구현하기.
image

객체

  • Component 인터페이스는 역할을 하는 Graphic은 해당하는 공통 operation인 move와 draw를 가지고 있습니다.
  • Leaf는 요소의 클래스(a.k.a. Component class)인 DotCircle은 simple element을 나타냅니다. Circle이 Dot을 상속 받았다사피, 모든 Component class는 다른 컴포넌트로 확장될 수 있습니다.
  • Container 요소의 클래스(a.k.a. Composite class)인 CompoundGraphic은 몇몇 sub-shape들로 이루어져 있습니다. 스스로 뭔가를 하기보다 요청을 하위 요소에 위임하는 방식으로 동작합니다.
  • Client인 ImageEditor는항상 component interface를 통해 shape element에 접근합니다. 따라서 Dot과 Circle과 같은 simple element인지 CompoundGraphic에 해당하는 complex element인지 모른채로 작업할 수 있습니다.

Applicability

🐞 트리 객체 구조를 구현할 때 Composite 패턴을 사용하세요.

⚡️ Composite에서는 동일한 공통 인터페이스를 공유하는 2가지 기본 element 타입을 제공합니다.

  • simple leaf
  • complex container: complex container는 leaf들 또는 다른 container들로 구성됩니다.

이 element type들로 재귀적으로 중첩된 객체구조를 트리로 나타낼 수 있도록 해줍니다.

🐞 client 코드에서 simple element & complex element 모두 일관되게 취급하고 싶을 때 Composite 패턴을 사용하세요.

⚡️ Composite 패턴을 통해 정의된 모든 element들은 동일한 인터페이스를 공유하고 있으므로, client는 작업 중인 객체의 구체적인 클래스를 고려할 필요가 없습니다.

How to Implement

  1. 어플리케이션의 코어 모델이 트리로 나타낼 수 있는 것이여야 한다.
  2. Simple element와 complex element 모두에 필요한 메소드 목록을 가진 Component interface를 선언합니다.
  3. Simple element를 나타내는 Leaf class를 생성합니다. 프로그램은 여러개의 서로 다른 Leaf class를 가질 수 있습니다.
  4. Complex element를 나타내는 Container class를 생성합니다. Container class에서는하위 요소의 reference를 저장해둔 배열을 제공해야합니다. 그리고 Component interface를 구현할 때, Container는 거의 모든 작업을 자식 요소에게 위임시켜야 합니다.
  5. 마지막으로, Container에 자식 요소를 추가/삭제하는 기능을 정의합니다. 이 operation들은 Component interface에 선언될 수 있습니다. 그렇다면 Interface Segregation Principle을 위반하게 됩니다. Leaf class에서 해당 메소드 구현을 비워둘 것이기 때문입니다. 그렇지만 Client가 트리를 구성(compose) 할 때 까지도, 모든 요소를 동일하게 대할 수 있게 됩니다.

Pro and Cons

  • ➕ 복잡한 트리 구조들에 대해 더 편리하게 작업할 수 있습니다: 폴리모르피즘과 반복을 통해 이점을 누리세요.
  • ➕ Open/Closed Prin­ci­ple: 이제 객체 트리에 존재하는 기존 코드에 영향을 즈지 않고도, 앱에 새로운 element type을 추가할 수 있습니다.
  • ➖ 서로 기능이 많이 다른 클래스에 대한 공통 인터페이스를 제공하는 것은 어려울 수 있습니다. 컴포넌트 인터페이스를 과도하게 일반화해야하는데, 그럴수록 인터페이스를 이해하기 어려워집니다.

React: props

  • In React props is short for properties
  • props are used to pass data from component to component.
  • props are Read-Only

example

  • <Image /> is one of React Native Component
  • <Image /> has source as props
<Image source={{uri:'https://dummyimage.com/600x400/000/fff'}/>

클린 아키텍처

클린 아키텍처

소프트웨어는 이해관계자들에게 행위 behavior, 구조 structure 라는 두가지 가치를 제공한다.
행위(기능) 를 통해서는 수익을 창출하거나 비용을 절감할 수 있다. 이를 위해 요구 명세서를 구체화하고 코드로 구현한다.
구조(아키텍처) 는 소프트웨어가 soft웨어 답게 추후에도 행위를 쉽게 바꿀 수 있도록 하기 위한 것 이다.

둘 중 무엇이 더 중요할까?

대체로 개발자들은 업무 관리자의 요구대로 기능을 우선 동작하게하는 데에 우선순위를 두곤 한다.
하지만 완벽하게 동작하지만 변경이 전혀 불가능한 프로그램과 동작은 하지 않지만 변경에 유연한 프로그램 을 비교해보자.
후자는 변경을 통해 동작하게 만들 수 있지만,
전자는 다음 요구사항이 왔을 때 변경이 불가능하므로 변화가 필요할 때 프로그램 전체를 폐기해야 할 것 이다.

주로 긴급한 것은 기능이지만, 구조는 중요하다.
�긴급한 것에 집중하다 중요한 것을 놓치지 않도록 주의해야한다.

프로그래밍 패러다임

프로그래밍 패러다임이란 개발자에게 관점을 갖게 해주는 규율로 프로그래밍을 하는 방법을 알려준다. 규율이란 지켜야 할 규칙이 있다는 뜻 이다. 프로그래밍 패러다임에서의 규율은 해야하는 것 이 아니라 하지 말아야하는 것 에 대해 말하며 코딩하는 방식을 한정시킨다.

지난 반세기 동안 발견된 프로그래밍 패러다임은 세가지가 있다. 1946년 앨런 튜링이 기계어로 코드를 작성했을 때부터 지금까지 프로그래밍 도구는 많은 변화가 있었지만, 프로그래밍 규칙은 변하지 않았다. 프로그램은 순차 sequence, 분기 selection, 반복 iteration, 참조 indirection 로 구성되는 것일 뿐입니다. 따라서 앞으로도 (적어도 프로그래밍에 제한을 주는) 프로그래밍 패러다임이 더 발견되는 일은 없을 것�이다.

구조적 프로그래밍 (Structured Programming)

제어흐름의 직접적인 전환에 부과되는 규율

데이크스트라는 인간의 인지적인 한계로 인해 요구되는 세부사항을 모두 감당하기 힘들다 것에 문제의식을 가지고, 이 문제를 풀기위해 수학적인 관점에서 접근했다. 수학적 원리인 증명 proof 를 활용하는 것 인데, 증명을 가능하게 만들려면 분할 정복 접근법을 사용해야만 했고, 분할정복 접근법을 사용하려면 증명가능한 모듈 단위로 프로그램을 분할 할 수 있어야 했다. 그런데 당시에는 무분별한 goto 문이 사용이 허용되어있어서 프로그램을 반증가능한 단위로 만들 수 없었다. 제어흐름이 순차적이지 않고 뒤죽박죽이였기 때문이다.

따라서 데이크스트라는 goto 문장의 좋은 사용방식인 분기( if / then / else )반복( do / while ) 을 발견했다. (최초로 발견한건 아님) 이 제어구조를 순차 실행과 결합하면 모듈을 증명가능하게 하는 단위를 만들 수 있다. 또한 이는 모든 프로그램을 만들 수 있는 최소의 제어구조에 해당한다.

구조적 프로그래밍은 순차, 분기, 반복이라는 세가지 제어구조를 따르는 것을 말한다.

결국 프로그램을 엄밀하게 증명하는 일은 일어나지 않았지만, 프로그램이 증명 가능한 단위로 분해될 수 있게 됨으로써, 테스트가 가능해졌다. 프로그램의 옳음을 증명하는 일은 일어나지 않았지만, 거짓임을 증명하는 과학적 방식을 활용할 수 있게 되었다. 우리는 테스트를 수행함으로써 작은 단위로 쪼개진 프로그램의 모듈을 거짓인지에 대해 증명을 시도한다. 테스트 결과 거짓이 아님이 확인되면 프로그램이 제 역할을 수행할 정도로는 참이라고 여기고 사용하는 것이다.

  • 더이상 사용하지 못하는 것: goto 문

객체 지향 프로그래밍 (Object-oriented Programming)

제어흐름의 간접적인 전환에 부과되는 규율

(소프트웨어 아키텍트 관점에서) 객체 지향은 다형성을 이용하여 시스템내의 소스 코드 간 의존성에 대한 절대적인 제어 권한을 획득할 수 있는 능력을 말한다.

객체 지향 언어가 있기 이전에도 다형성을 표현하는 방법은 있었다. 함수를 가르키는 포인터를 활용하는 방식이다. 객체 지향 언어가 최초로 다형성을 지원해준 것은 아니지만, 다형성을 더 안전하고 편리하게 사용할 수 있게 해준다. 사실 함수 포인터를 사용하는 것은 위험하기 때문이다. (매번 포인터를 초기화하고 포인터를 통해서 모든 함수(?)를 호출해야한다.)

다형성을 활용하지 못한다면 소스코드는 제어흐름에 따라 의존성이 결정된다. 고수준의 모듈이 저수준의 모듈에 의존할 수 밖에 없는 것이다. 다형성을 활용하면 이 문제를 해결할 수 있다.

중간에 인터페이스를 넣어주고 고수준 모듈이 인터페이스에 의존하도록 만든다. 그리고 저수준 모듈이 인터페이스를 상속받아 다형성을 이용해 저수준 모듈 나름의 구현을 하도록 한다. 그러면 더이상 의존성이 고수준 모듈에서 저수준 모듈로 흐르지 않는다.

의존성 역전을 활용하면 의존성을 원하는 대로 설정할 수 있다. 이를 통해 원하는 아키텍처를 구현할 수 있게 된다.

  • 더이상 사용하지 못하는 것: 함수 포인터

함수형 프로그래밍 (Functional Programming)

변수 할당에 부과되는 규율

함수형 프로그래밍 언어인 클로져로 정수 1부터 25까지의 제곱을 출력하는 코드

(printIn (take 25 (map (fn [x] (* x x)) (range)))))

객체 지향 언어로 구현한다면 흔히 볼 수 있는 제어 구조는 보이지 않고 온통 함수만 보인다.
또한 클로저에서는 x와 같은 변수가 한 번 초기화되면 절때 변하지 않는다고 한다. 함수형 언어에서는 변수가 변하지 않기 때문이다.

아키텍처를 고려할 때 이와 같은 변수의 불변성이 중요한 이유가 있다. 동시성 어플리케이션에서 만나는 모든 문제인 경합 조건, 교착상태 조건, 동시 업데이트 문제 모두 가변 변수로 인해 일어나는 문제이기 때문이다. 이러한 동시성 문제를 제어하기 위해 불변성을 다루는 것이 중요한 것이다.

우리는 불변 컴포넌트를 최대한 늘려서 안전지대를 넓혀두고, 최소화된 가변 컴포넌트에 동시성 문제에 대응할 수 있는 솔루션을 적용하는 방식을 활용할 수 있다.

  • 더이상 사용하지 못하는 것: 할당문

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.