ziglog

    Search by

    5월 2주차 기록

    May 14, 2022 • ☕️☕️☕️ 16 min read

    양평같은 방 아니고 진짜 양평


    배워가기

    워룸, WBS, 간트차트

    • 워룸(War Room)
      • 전쟁이 벌어졌을 때, 지휘관과 참모들이 모여 전쟁 상황을 한눈에 파악하고 작전을 세우는 곳이라는 의미다. 긴급한 일이나 위기 상황에 대처하기 위하여 마련한 상황실을 비유적으로 이르는 말.
      • * 작전실, 전시 작전상황실, 종합상황실으로도 불린다.
    • WBS
      • 업무 분류 체계(Work breakdown structure)는 종속 관계를 바탕으로 프로젝트 결과물이 나오기까지의 단계를 여러 계층으로 나눠 시각적으로 분류한 것이다. 즉, 프로젝트를 진행하기 위해(또는 결과를 위해) 필요한 정보들을 파악할 수 있도록 하는 딜리버러블 지향(결과물을 도출할 수 있도록 하는) 분업 구조를 의미한다.
      • 칸반보드, 타임라인, 간트 차트, 캘린더 등 특정한 수단을 활용하여 시각적으로 나타낼 수 있다.
    • 간트차트
      • 프로젝트 일정 추적관리를 위해 사용하는 도구로서, 각 업무별로 걸리는 시간(또는 걸릴것이라고 예상한 시간)을 가로 막대 형태(바형태)로 나타낸다. Karol Adamiecki의 하모노그램과 Henry Gantte의 공장 작업 소요시간 나타내는 차트 시스템이 통합되어 오늘날 간트 차트가 되었다. 또한 업무간의 관계도 알 수 있어서 종속관계(연관성)를 파악하기 쉽다. 보통은 일정(바), 담당자, 마일스톤, 업무간의 관계정도만 표현한다.
      • 간트차트는 프로젝트를 설계할 때 작성하는데에 유용하다. 정보를 많이 기입해야하면 한눈에 파악할 수 있다는 장점이 사라질 수 있다.

    ErrorBoundary는 await 함수의 에러만!

    ErrorBoundary는 await하지 않은 비동기 함수에서의 에러는 감지하지 못한다. 추가로 아래 2가지 경우에서도 에러를 감지하지 못한다.

    • 이벤트 핸들러
    • 비동기적 코드 (예: setTimeout 혹은 requestAnimationFrame 콜백)
    • 서버 사이드 렌더링
    • 자식에서가 아닌 에러 경계 자체에서 발생하는 에러

    await하지 않고 실행한 비동기 함수는 리액트의 render와 commit phase 밖에서 동작하기 때문이다. 우회적으로 await 하지 않은 비동기 함수의 catch 문에서 에러를 던지고 싶다면, hook 내부에서 에러를 던지는 방법으로 작성하는 방식이 있다.

    Copy
    setState(() => {
      throw new Error("hi");
    });

    이를 재사용 가능한 hook으로 만들면 다음과 같다.

    Copy
    const useAsyncError = () => {
      const [_, setError] = React.useState();
      return React.useCallback(
        (e) => {
          setError(() => {
            throw e;
          });
        },
        [setError]
      );
    };

    React의 render vs commit phase

    • render phase에서는 JSX 코드를 JavaScript 표현식으로 바꿔 Virtual DOM을 생성한다.
    • commit phase에서는 위 표현식을 실제 DOM에 반영한다. 👩‍🏫 이 모든 과정을 통틀어 재조정(reconciliation) 이라고 한다.

    Ref https://github.com/facebook/react/issues/14981#issuecomment-468452682 https://medium.com/trabe/catching-asynchronous-errors-in-react-using-error-boundaries-5e8a5fd7b971 https://dev.to/thee_divide/reconciliation-react-rendering-phases-56g2

    모노레포의 기본

    • 모노레포(monorepo)
      • 두개 이상의 프로젝트가 동일한 저장소를 사용하는 소프트웨어 개발 전략
      • 프로젝트 사이에 의존성이 존재하거나 동일한 도메인과 같은 정의된 관계가 존재한다.
    • 모노레포 도구(tools)
      • 모노레포를 구축하고 이를 쉽게 관리하고 유지할 수 있게하는 도구. 관리/속도/구조 등 여러 측면에서 나의 프로젝트와 궁합이 잘 맞는 도구를 선택하는 것이 좋다.
    • 모노레포 도구를 선택할 때 고려해야 할 것
      • 로컬 캐싱 - 같은 머신에서 같은 것을 두번 빌드하거나 테스트 하지 않는다.
      • 로컬 작업 오케스트레이션 - 여러 Task 를 올바른 순서로 병렬 실행할 수 있는 기능
      • 분산 캐싱 - 서로 다른 환경에서 캐시 아티팩트를 공유할 수 있는 기능
      • 분산 작업 실행 - 단일 시스템에서 실행되어 여러 시스템에 명령을 전달하는 기능
      • 변경에 영향을 받는 프로젝트(패키지) 감지 - 변경에 영향을 받는 프로젝트만 빌드/테스트한다.
      • 워크스페이스 분석 - 추가 구성 없이 시각적인 워크스페이스 그래프를 제공한다.
      • 의존성 그래프 시각화 - 프로젝트 및 Task 간의 의존 관계를 시각화한다.
      • 소스코드 공유 - 서로 다른 프로젝트 간에 소스코드를 쉽게 공유할 수 있다.
      • 코드 제너레이터 - 말그대로 코드 스캐폴딩이 가능하다.

    Ref https://monorepo.tools/

    Node 서버 활용하기

    기본적으로 노드 서버는 자바스크립트로 요청이 올 때, v8 엔진이 싱글쓰레드로 읽으므로 여러 프로세스를 동작하도록 해야한다. 만약 이게 싫다면 성능을 낮추고 작은 서버로 여러 인스턴스를 띄우는 것도 방법이다.

    pm2의 클러스터 모드를 활용해 여러 노드 프로세스를 띄울 수 있다. 클러스터 모드를 사용하면, 서버 안에 CPU가 처리할 수 있는 프로세스의 개수 안에서 프로세스 당 하나씩 노드 서버를 띄울 수 있다.

    implicit props vs explicit props

    implicit props는 @types/react에서 자동으로 추가되는 암시적인 props를 가리킨다.

    Copy
    <Input key=’first’ />

    explicit props는 명시적으로 props interface에 작성되어 있는 props를 의미한다.

    Copy
    interface InputProps { type: string; }
    
    const Input: React.FC<InputProps> = ({ type }) => <input type={type} />
    
    <Input type="search" />

    심볼릭 링크 vs 하드링크

    • 심볼릭 링크는 원본 파일이 삭제되거나 경로가 바뀔 때 link가 깨진다
    • 하드 링크는 원본 파일과 동일한 inode를 사용해서 원본 파일이 삭제되어도 hard link된 파일은 삭제되지 않아 접근이 가능하다.

    next-transpile-modules

    빌드되지 않은 형태의 TypeScript 파일을 직접 임포트해서 사용할 수 있다.

    Nextjs는 기본적으로 외부 패키지를 트랜스파일하지 않는다. next-transpile-modules는 Nextjs에서 지원하는 모든 확장자의 트랜스파일을 지원한다. (.js .jsx .ts .tsx .mjs .css .scss .sass)

    모노레포 환경에서 다른 워크스페이스에 있는 컴포넌트를 사전 트랜스파일링 없이 바로 가져오고 싶을 때 유용하다.

    Copy
    // shared-ui/components/Button.js
    function Button(props) {
      return <button type="button">{props.children}</button>;
    }
    
    export default Button;
    Copy
    // next.config.js
    const withTM = require("next-transpile-modules")(["shared-ui"]);
    module.exports = withTM();

    Ref https://www.npmjs.com/package/next-transpile-modules

    pnpm

    npm, yarn과 같은 패키지 매니저 중 하나다.

    평탄하지 않은 node_modules를 생성하기 때문에 오직 직접적인 의존성을 가진 패키지만 사용된다. (자동완성도 실제로 설치한 패키지에서만 동작한다)

    모노레포 프로젝트에 적합하며, 빠르다는 장점이 있다.

    plug and play

    usb를 꽂으면 바로 연결되는 것처럼, “꽂으면 실행된다”는 의미로 사용한다. 하드웨어에서는 사용자가 별다른 조작이나 설정하지 않고 바로 연결됨을 의미한다.

    모노레포에서 이 개념은 상위 레포에서 필요한 모듈을 버전별로 모두 가지고 있고, 하위 레포에서 모듈 버전 정보만 소유한다는 의미를 가진다.

    하위 레포에서 해당 모듈을 사용할 때 가지고 있는 버전 정보를 기반으로 상위 레포에서 필요한 모듈을 가져오는 것을 의미한다.


    이것저것

    • MR 때 하지 않아도 되는 CI 작업이라면 MR 머지 후 release 브랜치에 커밋이 생긴 시점으로 해결하는 방법도 있다.

    • node 13버전 이하에서는 optional chaining, nullish 문법을 쓸 수 없다.

    • 디자인 토큰 - 브랜드 색상, 간격과 같은 스타일 변수를 말하는 용어로 쓰인다.

    • docusaurus - 예쁜 다큐먼트 사이트를 뚝딱 만들 수 있게 도와준다.

    • 웹뷰를 띄울 때 기존 웹뷰를 남기려면 query param에 shouldKeepPresentedView=true 옵션을 주면 된다.

    • Logical nullish assignment (x ??= y) - x가 nullish (null 또는 undefined일 때만) 값을 할당한다. (Ref)

    • sFTP - ssh 방식을 사용하여 안전하게 암호화된 구간에서 FTP(파일 전송)기능을 사용할 수 있다.

    • Location.hash - # 뒤에 나오는 식별자를 value로 하는 값

      • 해시라우터를 사용하면 주소 뒤에 #이 붙는다.
      • 별도 서버 설정 없이도 새로고침 시 오류가 나지 않는다.
    • webviewWillAppear 인터페이스는 웹뷰가 새롭게 띄워졌을 때가 아닌 focus out 됐다가 focus in 될 때 실행된다.

    • 스냅샷 테스팅(Snapshot Testing) - 어떤 기능의 예상 결과를 미리 정확히 포착해두고 실제 결과에 비교하는 테스트 방식

    • 타입스크립트에서 객체에 readonly 가 붙어도 객체의 필드는 수정이 가능하다.

    • File 객체의 type 필드 - MIME 타입을 반환한다. (Ref)

    • pps, ppsx 파일 확장자 - MS powerpoint XML을 가리킨다. (Ref)


    기타

    Turborepo로 모노레포 개발 경험 향상하기

    LINE에서 Turborepo로 모노레포를 개발한 경험을 공유한 글이다.

    Turborepo의 주요 미션은 모노레포 환경에서 개발자가 조금 더 쉽고 빠르게 개발할 수 있도록 빌드 도구를 제공하는 것입니다. 고급 빌드 시스템을 구축하는 복잡한 과정을 Turborepo가 대신해 주기 때문에 개발자는 복잡한 설정과 스크립트에 신경 쓰는 대신 개발에 더 집중할 수 있습니다.

    역시 개발자들은 귀찮음을 해결하기 위해 뭔가를 또 만든다..! 불편하면 불편한 대로 사는 나와는 참 다르다.

    Turborepo의 기본 원칙은 한 번 작업을 수행하며 수행한 계산은 이후 다시 수행하지 않는 것이다. 따라서 두 번째 실행할 때는 이전에 계산한 작업은 건너뛰고 이전에 캐싱해 놓은 로그를 다시 보여준다.

    마지막에 Performance가 향상된 모습을 보여주는데, 탐난다..! :amaze:

    Ref https://engineering.linecorp.com/ko/blog/monorepo-with-turborepo/

    Noto emoji font

    구글에서 공개했다. 흑백이고 가변 글꼴이어서 색상이나 굵기 설정도 가능하다.

    그리고 무엇보다 귀엽다!

    Ref https://developers.googleblog.com/2022/04/what-is-black-and-white-and-read-all.html

    리액트는 언제 컴포넌트를 렌더링 하나요?

    리액트에서 가장 기본이면서도 항상 골칫덩어리인 문제!

    😜 TL;DR

    리액트는 컴포넌트를 다음과 같은 상황일 경우 (재)렌더링한다.

    • 컴포넌트에 예정된 상태 업데이트가 있을 경우
      • 컴포넌트에서 사용된 커스텀 훅의 예정된 업데이트가 있을 경우도 포함
    • 부모 컴포넌트가 렌더링 되고 리렌더링에서 제외되는 기준에 충족하지 않을 경우. 제외되는 기준은 다음의 네 가지 조건을 모두 동시에 충족해야 한다.
      • 컴포넌트가 이전에 렌더링 되었어야 함. 즉, 이미 마운트 되었어야 함.
      • 변경된 props(참조)가 없어야 함.
      • 컴포넌트에서 사용하고 있는 context 값이 변경되지 않아야 함.
      • 컴포넌트에 예정된 상태 업데이트가 없어야 함.

    아래 예시가 특히 흥미로웠다!

    Copy
    default function App() {
      return (
        <Parent lastChild={<ChildC />}>
          <ChildB />
        </Parent>
      );
    }
    
    function Parent({ children, lastChild }) {
      return (
        <div className="parent">
          <ChildA />
          {children}
          {lastChild}
        </div>
      );
    }
    
    function ChildA() {
      return <div className="childA"></div>;
    }
    
    function ChildB() {
      return <div className="childB"></div>;
    }
    
    function ChildC() {
      return <div className="childC"></div>;
    }

    만약 Parent의 업데이트가 예정되어 있다면, 어떤 컴포넌트가 리렌더링 될까?

    당연히 Parent 자체는 업데이트를 예약한 컴포넌트이기 때문에 리액트에 의해 리렌더링 될 것이다. 하지만 모든 자식 컴포넌트 ChildA, ChildB, ChildC도 리렌더링 될까?

    🤔🤔🤔…

    답은 ChildA만 리렌더링된다!

    ChildA와 달리 ChildBChildC는 리렌더링 되지 않는다. 그 이유는 ChildBChildC가 렌더링 제외 기준을 충족했기 때문에 리액트가 렌더링을 건너뛰었기 때문이다.

    리액트의 렌더링 제외 기준을 알기 위해 이 글에서는 소스 코드까지 살펴보고 있다. 😵

    코드 내에서 리액트의 렌더링 제외 로직 관련 코드는 다음과 같다.

    Copy
    // 보류 중인 업데이트 또는 context가 없습니다. 여기서 렌더링을 제외합니다.
    didReceiveUpdate = false;
    return attemptEarlyBailoutIfNoScheduledUpdate(
      current,
      workInProgress,
      renderLanes
    );

    이 라인에 도달하기 위해서는 다음 조건이 충족되어야 한다.

    • current !== null
    • oldProps === newProps
    • hasLegacyContextChanged() === false
    • hasScheduledUpdateOrContext === false

    해석하면 대략 다음과 같다.

    • 컴포넌트가 이전에 렌더링되었다. 즉, 이미 마운트되었다.
    • 변경된 props가 없다.
    • 컴포넌트에서 사용되는 context 값 중 변경된 것이 없다.
    • 컴포넌트 자체에서 업데이트를 예약하지 않았다.

    처음 살펴보았던 예시에서,

    Copy
    function Parent() {
      return (
        <div>
          <Child />
        </div>
      );
    }

    Parent에서 반환된 <Child />는 Babel에 의해 React.createElement(Child, null)로 컴파일되고 { type: Child, props: {} }과 같은 형태의 ReactElement가 생성된다.

    props는 자바스크립트 객체이기 때문에 다시 생성될 때마다 참조가 변경된다. 기본적으로 React는 ===를 사용하여 이전 props와 현재 props를 비교한다. 따라서, props는 리렌더링 되면 다른 값으로 간주된다. 그렇기 때문에 Childprops의 일부로 Parent로부터 아무것도 받지 않지만, Parent가 리렌더링 될 때마다 여전히 리렌더링 된다. React.createElementChild를 위해 호출되고 새로운 props 객체를 만든다.

    하지만 만약 ChildParentprops로 전달할 수 있다면 어떻게 될까?

    Copy
    function App() {
      return (
        <Parent>
          <Child />
        </Parent>
      );
    }
    
    function Parent({ children }) {
      return <div>{children}</div>;
    }

    리액트에 의해 Parent가 렌더링될 때 Child에 대한 React.createElement 함수가 호출되지 않는다. 따라서 Child의 새로운 props가 생성되지 않고, 이는 위에서 언급한 네 가지 렌더링 제외 기준을 모두 충족시킨다.

    이것이 처음 예시에서 Parent가 업데이트를 예약할 때마다 ChildA만 리렌더링 되었던 이유다.

    Copy
    function Parent({ children, lastChild }) {
      return (
        <div className="parent">
          <ChildA /> // ChildA만 리렌더링된다.
          {children} // 리렌더링 제외
          {lastChild} // 리렌더링 제외
        </div>
      );
    }

    조금 복잡한 내용이다..!!

    두고두고 다시 읽어봐야겠다.

    Ref https://velog.io/@eunbinn/when-does-react-render-your-component

    Volta

    Node.js용 가상환경 같은 툴로, 프로젝트 구성원끼리 노드 버전 맞출 용도라면 nvm 대신 사용할 수 있다.

    Ref https://volta.sh/

    자바스크립트는 왜 프로토타입을 선택했을까

    이전에도 두어 번 읽어보았던 글인데, 볼 때마다 신선하고 정말 재미있다. 철학적 관점에서 프로그래밍 언어를 풀어내다니, 정말 간지…

    Ref https://medium.com/@limsungmook/자바스크립트는-왜-프로토타입을-선택했을까-997f985adb42

    파이스크립트(PyScript)

    아나콘다가 발표한 새로운 언어다. 이름이..!! 정말 끔찍한 혼종

    파이스크립트는 사용자가 파이썬과 표준 HTML을 결합하여 브라우저에서 풍부한 파이썬 애플리케이션을 만들 수 있도록 지원하는 프레임워크다. 브라우저 내 단일-포함(single-include) 방식으로 HTML 페이지에서 자바스크립트만큼 쉽게 파이썬 스크립트를 실행할 수 있도록 한다.

    파이스크립트를 사용한 예제가 올라왔다.

    Ref https://www.ciokorea.com/news/234899

    ts-error-translator

    혼란스러운 TS 로그를 사람이 보기 좋은 형태로 보여주는 VSCode 익스텐션이다.

    라떼는… 에러 로그도 불친절했다 이말이야

    Ref https://github.com/mattpocock/ts-error-translator

    Rayn Dahl의 “JavaScript Container” 한 마디

    한 마디가 아니고 투머치 주의…

    Ref https://www.facebook.com/xguru/posts/10227448129370092

    Nrwl이 가져간 lerna

    nx 를 만든 Nrwl에서 lerna를 이어서 관리한다고 한다.

    Ref https://github.com/lerna/lerna/issues/3121

    자바스크립트 함수 합성, 뭐가 그렇게 대단할까?

    그동안 함수형 프로그래밍에서 종종 보았던 compose(), pipe() 등의 함수를 만들면서 원리와 flow에 대해 설명한다.

    합성의 진정한 아름다움은 코드가 아니라 코드가 우리를 변화시키는데 있습니다. 코드에 대한 새로운 시각을 제공하기 때문입니다.

    뭔가 굉장한 세계가 열린 것처럼..!

    하지만 처음 접했을 때의 그 새로운 시야의 신비로움(?)은 잊지 못한다. 아직도 혼자 코드 쓰라 하면 못하지만.

    Ref https://junghan92.medium.com/번역-자바스크립트-함수-합성-뭐가-그렇게-대단할까-5a2664b7c2b8

    tc39/proposal-decorators

    벌써 stage3..!

    Ref https://github.com/tc39/proposal-decorators


    마무리

    오오.. 눈치채지 못했는데 이번주는 상당히 정보공유글이 많았네. 지난주는 씨가 말랐었는데… 정리하느라 힘들었다. 사실 평일 동안 집중도 잘 안 되고 😬

    이번주는 개발을 많이 하지 못한 것 같다. 마크업 정도 하고, 코드리뷰 하고, 그동안 해왔던 프로젝트 장애 대응 (프론트 문제는 아니었지만..!)하고… 사아알짝 지루했던 주였다.

    금요일엔 팀 전체 워크샵을 다녀왔다! 우형 오피스의 자랑인 <양평같은 방> 아니고 진짜 양평으로! ㅋㅋㅋ 맛있는 해물 칼국수도 먹고, 강릉이 아닌 양평(서종)의 테라로사에서 존맛탱이었던 까눌레도 먹었다. 입사 4개월 만에 드디어 만난 팀원분들이 엄청 반겨주셔서 행복했당 🥳

    빨리 깁스 풀고 싶다 🥺


    Relative Posts:

    5월 3주차 기록

    May 21, 2022

    5월 1주차 기록

    May 7, 2022

    zigsong

    지그의 개발 블로그

    RotateLinkImg-iconRotateLinkImg-iconRotateLinkImg-icon