반응형

내가 이걸 이해하고 있나? 싶어서

책읽는걸 그만두고 다른걸 해보다가 다시 내가 정리한 글들을 읽어봤다

 

체감상 10~30%만 실제로 응용하고 나머지는 안하고 있는 기분인데

%를 더 끌어올리게 노력해야겠다.

class

* SOLID

 

S : SRP(Single Responsibility Principle, 단일책임원칙)

하나의 객체는 하나의 책임(객체간 영향을 최소화하고 한가지 동작만을 수행)만을 가지도록 설계.

 

O : OCP(Open Closed Principle, 개방폐쇄원칙)

변경에는 닫혀있고 개방에는 열려있다.

→ 기존의 코드를 변경하지 않으면서 기능을 추가할 수 있도록 로직이 설계되어야 한다.

→ 클래스, 객체를 변경하지 않고도 클래스 환경을 변화할 수 있도록 구성한다.

 

L : LSP(Liskov Substitution Principle)

부모 클래스와 자식 클래스 간의 일관성이 있어야 한다.

→ 클래스를 재정의하지 않으며, 자식 클래스는 최소한 부모 클래스의 행위는 수행할 수 있어야 한다.

 

I : ISP(Interface Segregation Principle)

구체화보다는 추상화

→ 범용 인터페이스로 인해 여러 클라이언트(클래스)가 영향을 받기 보다는, 개별적인 클라이언트에 특화되어 서로의 영향을 최소화할 수 있도록 구성

 

D : DIP(Depedency Inversion Principle)

의존관계 역전 원칙

상위 계층(정책 결정)이 하위 계층(세부 사항)에 의존하는 전통적인 의존관계를 반전(역전)

→ 상위 모듈은 하위 모듈의 구현 내용에 의존하면 안 되고 상위 모듈과 하위 모듈 모두 추상화된 내용에 의존 

 

 

깨끗한 클래스를 만드는법에 대해 다루는 챕터

그렇다면 깨끗한 클래스란?

캡슐화 

클래스 외부 사용자는 사용하면서 내부 구현을 알 필요가 없고, 알아야할 이유도 없다.

 

클래스에서 꺼내와서 데이터 처리 X

객체에게 처리할 행위(method) 요청 O

 

캡슐화를 유지해야 좋은 클래스

풀어주는건 최후의 수단?

작은 클래스 

클래스는 함수와 마찬가지로 하나의 역할만(SRP), 작은 크기

 

- 만능 클래스보다는 하나의 책임

- 이름은 해당 클래스의 책임

- 모호한 이름 금지(Processor, Manager, Super 등) -> 여러 역할을 한다는걸 내포

- and, but 등 사용금지 -> 여러 역할을 한다는것 내포

 

응집도 up

보통 응집도를 높은 클래스 선호

클래스에 속한 메소드, 변수가 서로 의존하며 논리적인 단위로 묶인다

 

-> 큰 함수(클래스)를 여러개의 작은 역할로 나누면 응집도가 높아짐

 

변경하기 쉬운 클래스 & 변경으로부터 격리된 클래스

 

상세한 구현은 구현 요구사항이 바뀔때마다 위험에 빠진다 -> 인터페이스 & 추상 클래스를 통해

구현

 

클래스가 SRP, OCP 등 SOLID 원칙을 잘 만족했다면 요구사항이 변경되어도 유연한 대처가 가능 

 

결합도가 낮다 -> 변경에 영향받는 클래스가 격리되어 있어서 대처가 유연하다

 

ex) 레포지토리 패턴

https://0391kjy.tistory.com/39

 

Repository Pattern 이해하기

Repository Pattern? Repository(리포지토리) 패턴은 디자인 패턴 중 하나로, 데이터가 있는 여러 저장소(Local, Remote)를 추상화하여 중앙 집중처리 방식을 구성하고, 데이터를 사용하는 로직을 분리시키기

0391kjy.tistory.com

 

템플릿 메소드 패턴

https://gmlwjd9405.github.io/2018/07/13/template-method-pattern.html

 

반응형

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

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

1. 생성(Creational) 패턴

 

객체 생성 방식에 대한 패턴

생성 & 조합을 캡슐화해 특정 객체가 생성-변경되도 프로그램 구조에 영향을 

크게 받지 않게해서 유연성 제공

 

2. 구조(Structural) 패턴

클래스 & 객체를 조합해 더 큰 구조를 만드는 패턴

 

3. 행위(Behavioural) 패턴

객체 사이 상호작용하는 방식이나 관심사를 분리하는 방법

 

 

 

'바퀴를 재발명하지 말자'라는 말이 있는데 구현때 소프트웨어의 복잡성을 줄이려면 아는만큼 보이는거 같아서

앞으로 조금씩이라도 디자인패턴에 대해 공부하고 기록해놓으려고 한다.

 

tmi로 디자인 패턴을 몰라도 경험적으로 체득하고 사용한 경우도 있기는 있었다.

 

reference

 

https://medium.com/@nitinmuteja/part-1-gang-of-four-gof-software-design-patterns-9a2d1abe4dba

 

Part-1 Gang of Four (GOF) Software Design Patterns

Gang Of Four Design Patterns

medium.com

 

https://gmlwjd9405.github.io/2018/07/06/design-pattern.html

 

[Design Pattern] 디자인 패턴 종류 - Heee's Development Blog

Step by step goes a long way.

gmlwjd9405.github.io

 

반응형
반응형

요즘 갈 방향을 잃은 느낌이라 주의 환기 및 내가 주로 쓰던 명령어들을 복습겸 적어볼려고 한다.

git reset 

깃 공간을 크게 3가지로 나눈다면

 

1. Working Directory (create, update, Delete해서 작업한 파일이 반영되어 있는 디렉토리)

2. Staging Area(git add후 곧 commit 하기 이전의 디렉토리)

3. Git Directory(staging Area에 있는 작업이 commit되어 반영된 공간)

 

이라 할 수 있다.

이때 작업을 하다보면 각 공간(1->2, 2->3)에 잘못 반영될때도 있는데 이때 유용한 명령어가 바로 git reset이다.

 

git reset때 지워지는 영역

git reset은 크게 3가지이다.

 

사용 ex) git reset --soft HEAD^1(바로 이전 커밋(head)에 반영됨)

1. git reset --soft

 

commit을 잘못 반영했을때 Staging Area로 되돌릴 수 있는 명령어이다.

주로 commit명에 오타를 냈을때 많이 사용했다.

 

2. git reset --mixed

git reset의 default

해당 커밋의 repository~staging area의 영역에 있는 코드들을 전부 working directory에 반영한다.

(git add 이전 상태로 되돌린다)

 

주로 이전 커밋으로 돌아가서 staging area에 반영할 코드들을 기능별로(커밋을 나누고 싶을때)쪼개 commit할때 사용했다.

 

3. git reset --hard

작업을 아예 rollback할때 사용한다.

 

구현할때 어떤 이론을 세우고 작업을 했는데 내 이론이 틀렸을때 주로 사용했다.

 

git reflog

 

이걸 사용한경우는 손에 꼽히기는 한데 git reset --hard나 git 작업을 하다 잘못했을경우 롤백할 수 있는 매우 유용한 기능을 제공한다.

 

git rebase/git reset 등으로 커밋 이력이 삭제되었을때 git reflog를 하면 볼 수 있다

 

git cherry-pick 

 

다른 브랜치에 있는 commit을 선택적으로 반영할때 사용된다.

깃은 diff 가 아니라 각 커밋이 스냅샷이긴 한데 체리픽을 할때는 diff만 반영되는거(커밋 하나의 변경점) 같다.

 

tmi로 경험적으로 깨달은건데(틀릴수도 있음)

local에서 작업할때 git fetch 로 remote repository의 브랜치들을 가져와 있으면 local branch에 git cherry-pick 적용이 된다는 점이다. 

 

git rebase/merge/squash and merge

 

merge

 

왼쪽 3-way merge, 오른쪽 fast-forward merge

1. 3-way merge : 분기점이 있는경우 3-way merge를 해서 브랜치 두개를 합친다. (중간에 매개 commit인 merge commit이 하나 남는다)

2. fast-forward merge : 현 커밋보다 앞선 커밋들이 있는경우 fast-forward merge를 해서 앞선 커밋들을 충돌없이 따라간다.

그리고 commit id 는 그대로 남는것으로 알고 있다.

 

squash and merge

 

두개의 브랜치를 합칠때 합쳐지는 대상이 여러개의 커밋이라도 '하나의 커밋'으로 합쳐져서 반영되게 된다.

ex) squarsh and merge를 했을경우

그리고 그 커밋들은 커밋 내역에 합쳐져서 보이게 된다. 

 

rebase

 

일종의 되감기인데 두개의 브랜치가 한 줄로 이어지게 된다.

커밋 내역을 깔끔하게 보여줘서 rebase 팬들도 은근히 많이 있더라..

 

예시로

 

같은 부모 0 에서 시작한 1-2-3 이라는 A branch와

a-b-c라는 B 브랜치가 있다면

rebase 시 1-2-3-a-b-c 이런식으로 한줄로 된다.

 

그리고 Merge는 Commit ID가 보존되고, Rebase는 새로운 Commit이 생성되므로 Commit ID가 바뀐다

https://learngitbranching.js.org/?locale=ko 에서 테스트해보자. 

C3에서 나온 rebase branch(C4, C5)에서 C8을 rebase 했더니 C4', C5'로 각각 새로운 commit Id가 생성된것을 확인 가능하다. 

 

C3에서 나온 mege branch(C6, C7)에서 C9를 merge 하면 C10 가 새로 생기고(merge commit) 

C9의 commit Id가 바뀌지 않고 그대로 이어진것을 확인 가능하다.

git log --graph

이런식으로.. cui에서 그래프 형태로 보여주게 된다

협업할때 이걸 써서 브랜치 현황을 보여주면 소스트리를 쓰는 팀원이 아주 좋아죽는다

 

소스트리같은 소프트웨어로 브랜치를 더 깔끔하게 보는 방법이 있으니

이런거 쓰지말고 착한 깃린이 여러분들은 이걸 쓰세여ㅠㅠ

 

소스트리 링크) https://www.sourcetreeapp.com/

 

Sourcetree | Free Git GUI for Mac and Windows

A Git GUI that offers a visual representation of your repositories. Sourcetree is a free Git client for Windows and Mac.

www.sourcetreeapp.com

 

git push origin main -f 

 

reference

 

git reset

 

https://opentutorials.org/module/4032/24533

 

git reset --hard vs --mixed vs --soft - GIT4 - Reset & Revert

수업소개 reset은 head가 가르키는 branch가 가르키는 커밋을 변경하는 작업입니다. 이때 옵션을 --hard, --mixed, --soft 중 무엇으로 주느냐에 따라서 stage, working directory의 상태가 달라집니다. 여기서는

opentutorials.org

 

https://im-developer.tistory.com/182

 

[Git] Merge 이해하기 (Merge / Squash and Merge / Rebase and Merge)

회사에서 Git을 사용해서 형상 관리를 하고 있다. 그 동안 내가 개인 repository branch에 commit, push등을 해본 적은 많지만 다른 사람과 협업을 하면서 branch를 생성하고 master에 merge를 해본 적은 없어서

im-developer.tistory.com

 

https://stackoverflow.com/questions/34019195/git-pull-doesn-t-fast-forward-merge-even-though-there-are-no-conflicts

 

Git pull doesn’t fast-forward merge, even though there are no conflicts

I just performed a git pull from my master branch on a remote repo into the branch I'm currently working on locally via the command line. Unexpectedly Vim opened. I quit Vim. Following this, I che...

stackoverflow.com

https://www.tuwlab.com/ece/22218

 

[GIT] 병합하고 Commit 재정렬하기: cherry-pick, rebase, merge - ECE - TUWLAB

병합과 재정렬은 대개 한 Topic(작업 단위)의 작업이 끝난 다음, 작업 내용을 Master branch에 반영해야 할 경우 수행하는 작업입니다. 새로운 Topic에 대한 작업을 할 때는 대개 Master Branch에서 새로운 B

www.tuwlab.com

 

반응형
반응형

jest로 테스트를 공부해보고 있는데 몇개 안넣었는데 3~4초 이상이 걸리길래 

한번 찾아봤다

 

https://if1live.github.io/posts/escape-from-jest-jest-is-slow/

 

Jest 탈출기 - Jest는 느리다 · /usr/lib/libsora.so

개요 요새 작업하는 프로젝트에서 jest를 사용해서 유닛테스트를 돌린다. 프로젝트가 진행될수록 테스트가 점점 느려지더니 이제 유닛 테스트 한번 돌리는데 1분이 걸린다. 라이젠 붙은 좋은 컴

if1live.github.io

 

요약) 

jest는 각 VM (Executing JavaScript) - test case에서 import를 각각 하기 때문에 느리다..

 

홀리..

반응형

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

쓸만해보이는 태그, 속성들 (메모용)  (0) 2022.07.11
반응형

See the Pen Untitled by lodado (@lodado) on CodePen.

 

css으로 직접 만들어본 loading spinner

 

출처 : https://codepen.io/mandelid/pen/kNBYLJ

 

Super Simple CSS Spinner

Just recreating http://codepen.io/scottkellum/pen/tzjCK to learn how he did it....

codepen.io

반응형

'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
CSS 애니메이션 성능 개선  (0) 2022.01.27
반응형

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

 

예시 화면(by react-query로 제작)

 

react-query를 보면 data, loading, error 상태가 있고 로딩 화면, 에러 화면을 각각 보여줄 수 있다

리둑스와 리둑스 사가로 비슷한걸 연습겸 한번 만들어 보았다.

 

*혹시 redux-saga 가 익숙하지 않다면

https://mskims.github.io/redux-saga-in-korean/introduction/BeginnerTutorial.html

추천

 

우선 초기 constant 를 정의한다.

/* constrant.ts */

export const START_LOADING = 'loading/START_LOADING';
export const FAIL_LOADING = 'loading/FAIL_LOADING';
export const FINISH_LOADING = 'loading/FINISH_LOADING';

export const GET_ITEM = 'GET_ITEM';
export const GET_ITEMS = 'GET_ITEMS';

export const RESPONSE_STATUS = {
  REQUEST: {
    data: undefined,
    error: false,
    empty: false,
    loading: true,
  },
  FAILURE: {
    data: undefined,
    error: true,
    empty: false,
    loading: false,
  },
  SUCCESS: {
    error: false,
    loading: false,
  },
} as const;

 

RESPONSE_STATE는 각 비동기 조건(data, loading, error)때 가지고 있을 상태이다.

SUCCESS의 경우엔 fetch된 data를 가지고 있어야 하기 때문에 나중에 상태를 만들때 주입할 예정이다.

 

~LOADING constrant들은 각 조건때의 action이다.

GET_ITEM, GET_ITEMS는 각각 아이템 하나, 아이템 리스트를 받아오는 비동기 요청 action이다.

 

이제 action를 제작해보자.

// action.ts

export const LOADING_STATUS = {
  GET_ITEM,
  GET_ITEMS,
} as const;

export type LoadingStatusType = typeof LOADING_STATUS[keyof typeof LOADING_STATUS];

function getVaildRequestType(requestType: string): LoadingStatusType {
  return LOADING_STATUS[requestType];
}

export const startLoading = (requestType: string) => ({
  type: START_LOADING,
  payload: getVaildRequestType(requestType),
});

export const failLoading = (requestType: string) => ({
  type: FAIL_LOADING,
  payload: getVaildRequestType(requestType),
});

export const finishLoading = (requestType: string, response: []) => {
  return {
    type: FINISH_LOADING,
    payload: getVaildRequestType(requestType),
    response,
  };
};

 

getVaildRequestType을 쓴 이유는 action과 reducer를 추상화하고 비동기 요청때마다 기본 템플릿으로 재사용하기 위해서 저런 번거로운 방식을 사용한것이다. (requestType로 type를 보내준다.)

 

(사실 getVaildRequestType을 안쓰고 그냥 payload:requestType해도 되긴 하는데 확장성을 위해서(혹시 상태의 이름을 변경하고 싶을때 사용하라고) 넣었다)

 

 

reducer를 만약 재사용을 하지 않는다면 비동기 요청 하나하나마다 각각 reducer를 제작해야하는 번거로움이 존재한다. 

 

이것은 reducer를 보면서 자세히 설명한다.

LOADING_STATE의 역할도 reducer를 보면서 설명한다.

각 action에 넣어주는 requestType는 redux-saga에서 넣어준다

 

// reducer.ts

function setInitState() {
  const init = {};

  const { REQUEST } = RESPONSE_STATUS;
  // eslint-disable-next-line no-return-assign
  Object.keys(LOADING_STATUS).map((key) => (init[LOADING_STATUS[key]] = REQUEST));
  return init;
}

interface LoadingActionType {
  type: string;
  payload: string;
  response?: [];
}

export function asyncLoadingReducer(state = setInitState(), action: LoadingActionType) {
  const { type, payload, response } = action;
  const { REQUEST, FAILURE, SUCCESS } = RESPONSE_STATUS;

  switch (type) {
    case START_LOADING:
      return {
        ...state,
        [payload]: REQUEST,
      };

    case FAIL_LOADING:
      return {
        ...state,
        [payload]: FAILURE,
      };
    case FINISH_LOADING:
      return {
        ...state,
        [payload]: { ...SUCCESS, data: response, empty: isEmpty(response) },
        //isEmpty는 그냥 fetch된 데이터가 비었나 확인해주는 함수
      };
    default:
      return state;
  }
}

 

[payload] : ~~상태 를 사용해서 아까 보낸 getVaildRequestType의 파라미터마다 상태를 가질 수 있다. 

 

예를 들어 LOADING_STATE에 지금 GET_ITEM 과 GET_ITEMS라는 type를 지정해두고 이후 redux-saga에서 실행할때 해당 type를  requestType(payload)로 받아온다면 type마다 { data, loading, error } 결과값을 가지는 상태를 가질 수 있다!

(이게 무슨말인지 혼동된다면 아래의 redux-saga까지 보고오면 이해가 빠를것 같다)

 

GET_ITEM, GET_ITEMS 각각 type 하나마다 { START_LOADING, FAIL_LOADING, FINISH_LOADING } case 상태(RESPONSE_STATE)를 가진다. 

ex) GET_ITEMS만 ajax 요청을 받아오고 완료되었을때 상태 출력(case FINISH_LOADING), GET_ITEMS는 아직 요청을 보내지 않았다(case START_LOADING-(default)).

SUCCESS(case FINISH_LOADING)땐 아까 만든 상태에 data를 주입해서 반환해주자.

 

이제 redux-saga를 보자.

function* abstractGenerator({ ACTION, axiosRequest }) {
  yield put(startLoading(ACTION));

  try {
    const response = yield axiosRequest;
    yield put(finishLoading(ACTION, response.data));
  } catch (error) {
    yield put(failLoading(ACTION));
  }
}

function *getItemListGenerator() {
  yield abstractGenerator({ ACTION: GET_ITEMS, axiosRequest: call(getItemList) });
}

function *getItemByIdGenerator(status: { id: number; type: string }) {
  const { id } = status;
  //yield put ~~ 
  yield abstractGenerator({ ACTION: GET_ITEM, axiosRequest: call(getItemById, id) });
}

function* getItemLIstSaga() {
  yield takeLatest(GET_ITEMS, getItemListGenerator);
}

function* getItemByIdSaga() {
  yield takeLatest(GET_ITEM, getItemByIdGenerator);
}

export function* rootSaga() {
  yield all([getItemLIstSaga(), getItemByIdSaga()]);
}

 

비동기의 기본 로직을 잘 보면

function* abStractGenerator({ ACTION, axiosRequest }) {
  yield put(startLoading(ACTION));

  try {
    const response = yield axiosRequest;
    yield put(finishLoading(ACTION, response.data));
  } catch (error) {
    yield put(failLoading(ACTION));
  }
}

 

1. 데이터 fetch를 시작한다 - START_LOADING(action)

2. action(GET_ITEM, GET_ITEMS)에 따라 ajax 요청을 보내고,  - START_LOADING 

3. 데이터를 받아오는데 성공했다면 성공 action을 반환한다. - FINISH_LOADING 

4. 실패했다면 실패 action을 반환한다. - FAIL_LOADING

 

비동기 요청시 대다수의 redux-saga는 비슷한 로직으로 실행될것이다.

그럼 이 비동기 로직도 달라지는 값인 action과 ajax 함수 값만 파라미터로 주입해준다면 재사용을 할 수 있다.

 

그리고 여기서 action인 startLoading, finishLoading, failLoading에 넣는 ACTION이 아까 보았던 requestType의 정체다.

그렇게 넣으면 payload로 action이 들어가게 되고... asyncLoadingReducer에서 [payload]마다 로딩, 에러, 성공시 알맞은 상태를 반환한다.

 

이런식으로 1개의 reducer, 1개의 saga를 재사용해 n개 이상의 다른 비동기 요청을 처리할 수 있다.

 

그리고 ajax 함수들은 이런식이다.

export const getItemList = () => axios.get(API.GET.ITEMLIST); // API.GET ~ 는 주소

export const getItemById = (itemId: number) => {
  return axios.get(API.GET.ITEM, {
    params: {
      itemId,
    },
  });
};

 

예시 component) 

export function ItemBox() {
  const { asyncLoadingReducer } = useSelector((state: RootStoreType) => state);
  const disPatch = useDispatch();

  const itemRequest = asyncLoadingReducer[LOADING_STATUS[GET_ITEM]];
  const { data, empty, loading, error } = itemRequest;

  useEffect(() => {
    disPatch({ type: GET_ITEM, id: 1 });
  }, []);

  if (loading) return <div>loading</div>;
  if (empty) return <div>emptyData</div>;
  if (error) return <div>error</div>;

  return <div>{JSON.stringify(data)}</div>;
}

 

추가) 

import { createStore, combineReducers, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import { asyncLoadingReducer } from './reducer';
import { rootSaga } from './saga';

const configureStore = () => {
  const sagaMiddleware = createSagaMiddleware();
  const rootReducer = combineReducers({
    asyncLoadingReducer,
  });

  const store = createStore(rootReducer, applyMiddleware(sagaMiddleware));
  sagaMiddleware.run(rootSaga);
  return store;
};

const rootStore = configureStore();

export type RootStoreType = ReturnType<typeof rootStore.getState>;
export default rootStore;

 

해본 후기)

 

그냥 react-query 쓰자

 

같이 읽으면 좋은 글)

 

https://techblog.woowahan.com/6339/

 

Store에서 비동기 통신 분리하기 (feat. React Query) | 우아한형제들 기술블로그

오늘은 주문에서 사용하는 FE 프로덕트의 구조 개편을 준비하며 FE에서 사용하는 Store에 대해 개인적인 고민 및 팀원들과 검토하고 논의했던 내용을 소개합니다. 이 과정에서 생긴 여러 가지 의

techblog.woowahan.com

 

반응형

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

react 17(개인 공부용)  (1) 2022.06.09
React18(개인 공부 메모용)  (0) 2022.06.09
react TMI  (0) 2022.04.13
drag and drop으로 창 크기 조절  (0) 2022.03.18
redux 기본 구조  (0) 2022.02.02

반응형

 

CORS는 많이 들어봤는데

CORB란것을 '사이트 격리'에 대해 알아보다가

새로 알게 되었다.

 

참고) 사이트 격리

 

- It ensures that pages from different websites are always put into different processes.

- It also blocks the process from receiving certain types of sensitive data from other site

 

즉, Chrome's Site Isolation effectively makes it harder for untrusted websites to access or steal information from your accounts on other websites.

 

Cross-Origin Read Blocking(CORB)

 

Cross-Origin Read Blocking (CORB) is an algorithm that can identify and block dubious 
cross-origin resource loads in web browsers before they reach the web page.

 

For example, it will block a cross-origin text/html response requested 
from a <script> or <img> tag, replacing it with an empty response instead.

 

출처 : https://developers.google.com/web/updates/2018/07/site-isolation

 

즉, 웹에서 cross origin의 data resource(xml, html, json 등)를 읽어와 사용하지 못하도록 브라우저에서 막는 동작이다.

 

원리 

 

CORB가 어떻게 동작하는지 알아보자.

보통 web client는 서버에 두가지의 요청을 보낸다.

 

  1. data resources such as HTML, XML, or JSON documents
  2. media resources such as images, JavaScript, CSS, or fonts

보통 1번은 SOP & CORS 설정에 따라 브라우저에 의해 blocking 되거나 보이게 된다.

(참고로 2번 media resources들은 cors에 상관없이 요청 가능하다. ex-JSONP)

 

조건 

그리고 CORB는 위 조건을 만족한다면

renderer processa cross-origin data resource를 받아와 사용하는 것을 금지한다.

(a new security feature that prevents the contents of balance.json from ever entering the memory of the renderer process memory based on its MIME type.)

 

참고)

X-Content-Type-Options: nosniff는 Microsoft에서 제안하는 확장 헤더이며 웹서버가 보내는 MIME 형식 이외의 형식으로 해석을 확장하는 것을 제한하는 크로스사이트스크립트 방어법이다.

 

즉, nosniff 옵션이 켜있다면 브라우저는 이게 HTML, XML, JSON중 하나인것으로 Content-type 종류로 인하여 헷갈리지 않고 바로 확정 지을 수 있다.

(가끔 어떤 서버는 이미지에 대해 text/html로 잘못 분류하기도 한다. 이걸 방지 가능)

 

이점 

 

CORB를 사용하면 다음과 같은 이점이 있다.

 

- Mark responses with the correct Content-Type header.

- out of sniffing by using the X-Content-Type-Options: nosniff header.

- 보안! (In browsers with Site Isolation, it can keep such data out of untrusted renderer processes entirely, helping even against side channel attacks like Spectre)

예시

그럼 예시 데모를 한번 보자.

 

https://anforowicz.github.io/xsdb-demo/index.html

 

CORB demo

Demo of CORB This page demonstrates how Cross-Origin Read Blocking (CORB) works. Please see one of the following resources for more information about CORB: Repro steps to trigger CORB: Make sure that CORB is active In Chrome M68 and later CORB is active by

anforowicz.github.io

 

<button> Add 1 <img src="https://www.chromium.org/"> </button>
<button> Add 2 <img src="https://www.w3.org/.../dummy.pdf"> </button>

 

들어가서 버튼을 한번 눌러보면

CORB 차단이 뜬다.

 

위 버튼들은 data resource(text/html, application/pdf) 요청을 cross-origin 서버에 보내는 버튼들이고, CORB에 의해 막히게 된다.

그리고 CORS와 동일하게 정상적인 요청이 왔어도 (status 200) 브라우저에서 막도록 구현된 것을 확인할수 있다.

 

 

tmi)

현재 tistory 스킨에서 영어를 읽으려니 눈이 아프다 -_-;

 

 

함께 읽으면 좋은 글)

 

CORS

https://beomy.github.io/tech/browser/cors/

 

[Browser] CORS란?

이번 포스트에서는 교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)에 대해 이야기해보도록 하겠습니다. 아래 사진과 같은 에러를 보신 적이 있으셨을 수도 있습니다.

beomy.github.io

 

reference 

 

https://chromestatus.com/feature/5629709824032768

 

https://stackoverflow.com/questions/18337630/what-is-x-content-type-options-nosniff

 

https://webhack.dynu.net/?idx=20161120.001&print=friendly 

 

https://bingbingba.tistory.com/8

 

https://developers.google.com/web/updates/2018/07/site-isolation

 

Site Isolation for web developers  |  Web  |  Google Developers

Chrome 67 on desktop has a new feature called Site Isolation* enabled by default. This article explains what Site Isolation is all about, why it’s necessary, and why web developers should be aware of it.

developers.google.com

 

반응형
반응형

ES6에서 도입된 제너레이터(Generator) 함수는 이터러블을 생성하는 함수이다.

제너레이터 함수를 사용하면 이터레이션 프로토콜을 준수해 이터러블을 생성하는 방식보다 간편하게 이터러블을 구현할 수 있다.

기존 Symbol iterator 로 피보나치 수열 구현

function fibonacci(maxi) {

  let [first, second] = [0,1];

  return {
    [Symbol.iterator](){return this;},
    next() {
      [first, second] = [second, first+second];
      return {value: first, done : first>=maxi};
    }
  }
}

const Fibo = fibonacci(1000);

while(true){
    const {value, done} = Fibo.next();
    if(done) 
        break
    console.log(value);
}
/* console 결과
VM242:20 1
VM242:20 1
VM242:20 2
VM242:20 3
VM242:20 5
VM242:20 8
VM242:20 13
VM242:20 21
VM242:20 34
VM242:20 55
VM242:20 89
VM242:20 144
VM242:20 233
VM242:20 377
VM242:20 610
VM242:20 987
*/

이터레이션 프로토콜)

 

Iteration & for...of | PoiemaWeb

ES6에서 도입된 이터레이션 프로토콜(iteration protocol)은 데이터 컬렉션을 순회하기 위한 프로토콜(미리 약속된 규칙)이다. 이 프로토콜을 준수한 객체는 for...of 문으로 순회할 수 있고 Spread 문법의

poiemaweb.com

이제 이 코드를 Generator로 변환해보자.

Generator로 변환

function* counter() {
  let count = 0;
  console.log(count);
  yield count++;                  
  console.log(count);
  yield count++;                 
  console.log('done'); 
}

const cnt = counter();

cnt.next(); // {value: 0, done: false}
cnt.next(); // {value: 1, done: false}
cnt.next(); // {value: undefined, done: true}

파이썬을 해봤다면 yield 문에 대해 한번은 들어봤을것이다.

우선 제네레이터에 대해 간략히 설명하자면

 

일반 함수와 같이 함수의 코드블록을 한번에 실행하지 않고 필요할때 재시작할 수 있는 특수한 함수이다.

value 값으로 yield 값이 리턴되고, done 값으로 언제 끝날지 알려주게 된다.

 

generator를 사용하면 

다음과 같은 방식으로도 구현 가능하다.

 

function *ex(){

  let a = yield;
  let b = yield;
  yield a+b;
}

const test = ex();

test.next();
test.next(1); // 인자전달
console.log(test.next(2)); // {value: 3, done: false}

시작지점을 알려준 뒤 

인자로 generator 안에 값을 넘겨줄수도 있다.

 

그럼 fibo 수열을 다시 generator로 구현해보자.

 

 function *fibonacci(){

  let [first, second] = [0,1];
  
  while(true){
    [first, second] = [second, first+second];
    yield first;
  }
}

const test = fibonacci();

test.next(); // 1
test.next(); // 1
test.next(); // 2
test.next(); // 3
...

코드가 매우 간략해진것을 확인 가능하다.

generator를 활용해서 무한 수열(Lazy Evaluation), 비동기 처리를 쉽게 활용 가능하다.

다만 좀 더 편리한 async/await 가 생겨서 generator 만으로 비동기 처리를 하지는 않는 편이다.

 

또한 redux-saga 등 여러 라이브러리에서 사용한다.

 

reference 

 

이터레이션 프로토콜

 

Iteration & for...of | PoiemaWeb

ES6에서 도입된 이터레이션 프로토콜(iteration protocol)은 데이터 컬렉션을 순회하기 위한 프로토콜(미리 약속된 규칙)이다. 이 프로토콜을 준수한 객체는 for...of 문으로 순회할 수 있고 Spread 문법의

poiemaweb.com

 

https://poiemaweb.com/es6-generator

 

Generator | PoiemaWeb

ES6에서 도입된 제너레이터(Generator) 함수는 이터러블을 생성하는 함수이다. 제너레이터 함수를 사용하면 이터레이션 프로토콜을 준수해 이터러블을 생성하는 방식보다 간편하게 이터러블을 구

poiemaweb.com

 

반응형
반응형

원래 redux를 처음에 공부하다가 

부스트캠프에서 프로젝트할때 recoil를 도입해서 사용했었는데

recoil이 나온지 얼마 안되다보니

redux의 기본적인 틀에 대한 코드만 메모해두려고 한다.

 

redux의 핵심 개념 - flex 패턴

 

사용자와 상호작용을 하다보며 view가 가끔씩 state을 업데이트해나갈때가 있는데,

그 영향이 다른 view나 state를 연쇄적으로 업데이트해서 서로 상호작용을 일으켜 의도치 않은 

버그나 결과를 내놓는 경우가 있었다

 

즉, 공을 튀기면 어느곳으로 튕겨나갈지 모르는 연쇄적인 반응이 일어났던것이다.

그래서 연쇄적 업데이트를 방지하고 단방향 데이터 흐름인(undirectional data flow) 인 flex 패턴이 탄생했다.

redux는 flex 패턴을 활용한 유명한 라이브러리이다.

 

Flux는 단방향으로 데이터가 흐르게 하는 구조이다.

redux는 크게 4가지 파트로 이루어져 있다.

 

상태 변경 정보인 Action

Action을 Store 에 반영하는 Dispatcher

Action을 처리해서 상태를 변경시키는 reducer

상태를 저장하는 Store

 

 

view layer에서 상태를 변경하고 싶다면 정해진 Action을 dispatch에 담아 호출한다. 

그럼 Reducer에서 그 액션을 처리하고 상태를 변경하여 store에 반영한다.

 

이제 연쇄적인 양방향 데이터 흐름을 단방향 데이터 흐름으로 바꾸었고, side effect가 없는

순수함수적인 개념으로 동작한다.

 

 

 

 

그림이니 눌러도 작동 안합니다 😂

그럼 버튼을 누르면 숫자가 늘어나거나 줄어드는 간단한 화면을

코드로 구현해보자.

Action

const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';

 

Action 명은 그냥 unique한 식별자를 가진 이름으로 구현하면 된다.

옛날에 수학 시간에 배운 함수를 떠올려보자.

 

함수 F 에 x 를 넣으면 y가 나온다는 수학 공식을 떠올리면

항상 같은 x를 넣으면 같은 y가 나온다.

F(x)=y

 

정해진 Action과 파라미터를 dispatcher에 넣으면 (상태가 같다면) 항상 같은 결과가 나오는것을 기대할 수 있어야 한다.

즉, 함수형 패러다임 개념을 일부 가져왔다.

강제된 법칙은 아닐테지만 의도치않은 버그를 보고싶지 않다면 따르는것이 좋다.

 

function increment(value: number) {
  return { type: INCREMENT, payload: { value } };
}

function decrement(value: number) {
  return { type: DECREMENT, payload: { value } };
}

해당 방식으로 action과 payload를 미리 정의할수도 있다.

payload는 action 이외에 view에서 받고 싶은 파라미터이다.

 

간단한 수학공식으로 예를 들면

F(x, a) = x + a 라고 볼 수 있다.

 

reducer

const initState = {
  value: 0,
};

const reducer = (state = initState, action) => {
  const { type, payload } = action;
  const { value } = state;

  switch (type) {
    case INCREMENT:
      return { ...state, value: value + payload.value };
    case DECREMENT:
      return { ...state, value: value - payload.value };
    default:
      return state;
  }
};

 

reducer는 state와 action을 받아서

알맞은 action에 따라 연산을 한 후 값을 반환한다.

 

아까 설명한 F(x)=y 의 함수(F) 역할을 하는 셈이다.

state의 초기값은 매개변수로 넣은 객체값이고, 이후 리둑스 라이브러리에서 자체적으로 관리와 갱신을 해주게 된다.

그리고 switch문 내부 가독성을 위해

case문 하나 하나 함수를 구현하는것을 추천한다.

store

const store = createStore(
  combineReducers({
    reducer,
  }),
);

store는 리엑트의 '전역' 상태 state라 보면 이해가 편하다.

store는 한개만 있어야 한다. (a single source of truth)

 

만약 reducer를 너무 크게 만들지 않고 기능별로 쪼개고 싶다면 combineReducer를 활용해서 합친다.

 

dispatcher

 

import { Provider, useDispatch, useSelector } from 'react-redux';

function Test() {
  const { value } = useSelector((state) => state.reducer);
  const dispatch = useDispatch();

  return (
    <div>
      <button
        onClick={() => dispatch({ type: INCREMENT, payload: { value: 10 } })}
      >
        up 1
      </button>

      <button onClick={() => dispatch(increment(10))}>up 10</button>
      <button
        onClick={() => dispatch({ type: DECREMENT, payload: { value: 10 } })}
      >
        down
      </button>

      {value}
    </div>
  );
}

ReactDOM.render(
  <Provider store={store}>
    <Test />
  </Provider>,
  document.getElementById('root'),
);

 

dispatcher는 미리 action을 받아서 reducer를 통해 상태를 갱신한다.

함수형 컴포넌트에서 react-redux 의 useSelector, useDispatch hook을 사용하면 쉽게 구현 가능하다.

 

      <button onClick={() => dispatch(increment(10))}>up 10</button>
      <button onClick={() => dispatch({ type: DECREMENT, payload: { value: 10 } })}>
        down
      </button>

위 코드 중간에 해당 방식처럼 dispatch에 넣는 방식으로는 함수를 쓸 수도 있고, 아니면 객체 리터럴을 정해진 형식대로 그대로 넣어도 된다.

 

(무슨 방식이든 내가 기존에 구현했던 reducer와 매칭이 잘되야 한다.)

 

나는 미리 구현된 함수를 넣는 방식을 추천한다.

남이 봤을때 dispatch만 봐서 무슨 역할을 하는지 이해가 어려울 수 있는데,

잘 명시된 함수 명으로 힌트를 주는 방식으로 구현하는게 유지보수및 협업 측면에서 좋다고 생각된다.

(위 코드는 예시 코드이니 함수명이 매우 간결하다 😂)

 

그외

 

개인적으로 

action, state, reducer 등을 한 파일에 몰아넣지 말고 

각각 모듈화해서 분리(action은 action끼리, reducer는 reducer 끼리)해서 파일구조를 짜는걸 추천한다.

 

그리고 redux-toolkit 이라는 redux를 보다 쉽게 사용 가능하게 도와주는 라이브러리도 있다.

다른 라이브러리는 redux 기반으로 설명 되어 있는 글이 많아서 처음 배우고 있을때 보면 엄청 헷갈린다.

redux가 어느정도 익숙해지면 나중 생산성 향상을 위해 도입해보는거도 나쁘지 않는거 같다.

 

같이 읽어보면 좋을 글)

 

전역 상태를 왜 쓰는지 -> props drilling 해결

https://medium.com/front-end-weekly/props-drilling-in-react-js-723be80a08e5

 

Props Drilling In React.Js

What Is Props Drilling? And How To Sidestep It?

medium.com

 

기존 react는 (model이 없는) VVM 혹은 VC 패턴이라고 보는게 정확하다는 의견도 있다.

https://stackoverflow.com/questions/51506440/mvvm-architectural-pattern-for-a-reactjs-application

 

MVVM architectural pattern for a ReactJS application

I'm a semi-senior react and JavaScript developer, I've made several Universal react application. Today our CTO told me: Do you use a software architectural pattern for your application? I've no a...

stackoverflow.com

 

reference

 

https://redux.js.org/tutorials/fundamentals/part-1-overview

 

Redux Fundamentals, Part 1: Redux Overview | Redux

The official Fundamentals tutorial for Redux: learn the fundamentals of using Redux

redux.js.org

 

 

https://sihus.tistory.com/37

 

Flux Design Pattern 이해하기 (+ 단방향, 양방향 데이터 바인딩)

MVC 디자인 패턴이 아닌 Redux의 주개념이자, 리액트를 사용하면서 컴포넌트끼리 데이터를 교류할 때, 글로벌 이벤트 시스템을 설정하는 방법인 Flux 디자인패턴에 대해 알아보고 왜 facebook에서 reac

sihus.tistory.com

 

https://yoonho-devlog.tistory.com/171

 

Redux 개념 이해하기

Flux 패턴 redux는 Flux 패턴의 구현체입니다. 따라서 Flux 패턴을 먼저 이해하면 자연스럽게 Redux를 이해할 수 있습니다. facebook은 우리가 흔히 알고 있는 MVC 패턴을 사용하는 대신, Flux라는 새로운 방

yoonho-devlog.tistory.com

 

https://hanamon.kr/redux%EB%9E%80-%EB%A6%AC%EB%8D%95%EC%8A%A4-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC/

 

Redux(리덕스)란? (상태 관리 라이브러리) - 하나몬

Redux(리덕스)란? 무엇인지 부터 간단한 실습까지 (상태 관리 라이브러리 리덕스 알아보기) ⚡️ Redux(리덕스)란? Redux(리덕스)란 JavaScript(자바스트립트) 상태관리 라이브러리이다. Redux(리덕스)의

hanamon.kr

 

 

반응형

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

react 17(개인 공부용)  (1) 2022.06.09
React18(개인 공부 메모용)  (0) 2022.06.09
react TMI  (0) 2022.04.13
drag and drop으로 창 크기 조절  (0) 2022.03.18
redux, redux-saga로 로딩, 에러 페이지 구현  (0) 2022.02.12

+ Recent posts