ziglog

    Search by

    10월 2주차 기록

    October 14, 2022 • ☕️☕️ 12 min read

    추운 날씨 좋아


    배워가기

    Table 내의 내용 없는 셀(td) 표현

    테이블에 들어갈 데이터에 값이 없거나 값이 0인 경우에는 아무것도 없는 <td></td>와 같이 빈 셀로 표현하는 경우가 있다. 하지만 이 경우 CSS에서 border-collapse: collapse를 사용하지 않으면 설정한 border가 제대로 표현되지 않을 수 있으며, 스크린 리더를 사용할 경우 내용 없는 빈 셀은 테이블의 구조의 파악을 어렵게 만든다.

    값이 없는 경우는 ‘없음’과 같은 텍스트를 삽입한 후, CSS를 사용하여 텍스트를 숨겨서 제공하면 디자인상의 문제 없이 table의 정보 접근성을 높일 수 있다.

    tsconfig.lib.json

    타입스크립트가 빌드될 때 참조하는 tsconfig.json의 컴파일 옵션중에 lib이라는 항목이 있다.

    Copy
    // tsconfig.json
    {
      "CompilerOptions": {
        "target": "es5",
        "module": "commonjs",
        "lib": [
          "dom",
          "es5",
          "es2015.promise"
        ]
      }
    }

    lib 파일들은 보통 설치한 타입스크립트 모듈에 존재하며, 타입스크립트는 빌트인 JS API들이나 브라우저 환경에 대한 것들의 타입 정의를 포함하고 있다.

    Ref

    docker-compose로 다중 컨테이너 애플리케이션 만들기

    docker-compose.yml을 사용하여 다중 컨테이너 애플리케이션을 만들 수 있다.

    docker의 volume이란, 도커 컨테이너에 의해 생성되는 데이터를 유지하는 데 선호되는 메카니즘이다. volume의 내용물은 주어진 컨테이너의 라이프사이클 바깥에 존재한다.

    일반적으로 docker container는 컨테이너 내부에 데이터를 관리하므로, 컨테이너가 파기되면 데이터가 모두 날라가게 된다. 이는 mysql 같은 데이터 스토리지를 사용할 경우 위험하게 되는데, 이를 방지하기 위해 따로 볼륨을 설정해서 데이터를 저장해줘야 한다

    Ref https://joont92.github.io/docker/volume-container-추가하기/

    nest registerAs

    • namespace에 configuration을 할 때 사용한다.

    • ConfigModule을 이용해서 여러 개의 커스텀 configuration 파일을 정의하고 로드할 수 있다.

    • nesting된 복잡한 configuration 객체들을 사용하는 대신, registerAs 를 사용하여 namespace의 configuration을 정의할 수 있다.

      Copy
      export default registerAs("database", () => ({
        host: process.env.DATABASE_HOST,
        port: process.env.DATABASE_PORT || 5432,
      }));

    Ref https://docs.nestjs.com/techniques/configuration#configuration-namespaces

    IoC, DI, DIP

    👩‍🏫 IoC (Inversion of Control)

    제어의 역전은 프로그래머가 작성한 프로그램이 재사용 라이브러리의 흐름 제어를 받게 되는 소프트웨어 디자인 패턴이다. 제어의 역전이 적용된 구조에서는 외부 라이브러리의 코드가 프로그래머가 작성한 코드를 호출한다.

    모듈을 작성할 때, 모듈과 외부 프로그램의 결합을 고민할 필요 없이 모듈의 목적에 집중할 수 있으며, 모듈을 바꾸어도 다른 시스템에 부작용을 일으키지 않는다.

    예를 들어, 웹 개발에서 많이 사용하는 프레임워크는 규칙에 따라 구성요소를 등록하면, 프레임워크에서 이 구성요소를 가져다 써야 한다. (DOM 렌더링에 관여하는 React가 바로 적합한 예시!)

    코드 상에서 IoC는, 클래스의 생성자를 직접 호출해 인스턴스를 생성하는 방법이다. IoC는 누가 작업을 수행하느냐에 대한 이야기다.

    👩‍🏫 DI (Dependency Injection)

    의존성 주입은 프로그래밍에서 구성요소 간의 의존 관계를 소스코드 내부가 아닌 외부의 설정 파일 등을 통해 정의하는 디자인 패턴이다.

    IoC의 한 형태가 DI다. 마틴 파울러는 다음 세 가지 의존성 주입 패턴을 제시한다.

    • 생성자 주입: 필요한 의존성을 모두 포함하는 클래스의 생성자를 만들고 그 생성자를 통해 의존성을 주입한다.
    • setter를 통한 주입: 의존성을 입력받는 setter를 만들고 이를 통해 의존성을 주입한다.
    • 인터페이스를 통한 주입: 의존성을 주입하는 함수를 포함한 인터페이스를 작성하고 이 인터페이스를 구현하도록 함으로써 실행 시에 이를 토해 의존성을 주입한다.

    즉 DI는 의존성을 어떻게 주입할 것인가에 대한 문제다.

    👩‍🏫 DIP (Dependency Inversion principle)

    객체지향 프로그래밍에서 의존 관계 역전 원칙은 소프트웨어 모듈들을 분리하는 특정 형식을 지칭한다. 상위 계층(정책 결정)이 하위 계층(세부사항)에 의존하는 전통적인 의존 관계를 역전시킴으로써 상위 계층이 하위 계층의 구현으로부터 독립되게 할 수 있다. (😲 클린 아키텍처 19장 ‘정책과 수준’에 나온 내용과 같다. 좋은 아키텍처는 각 컴포넌트를 연결할 때 의존성의 방향이 저수준 -> 고수준 컴포넌트가 되어야 한다.)

    • 상위 모듈은 하위 모듈에 의존해서는 안된다. 상위 모듈과 하위 모듈 모두 추상화에 의존해야 한다.
      • 어디서 많이 봤다 했더니, 소프트웨어 설계 원칙 SOLID의 마지막 기법(D)에 해당하는 내용이었다! 소스 코드는 구체화된 것에는 의존하지 말아야 한다. 안정된 소프트웨어 아키텍처는 안정된 추상 인터페이스에 의존한다.
    • 추상화는 세부사항에 의존해서는 안된다. 세부사항이 추상화에 의존해야 한다.

    DI는 DIP를 구현하는 방법 중 하나다. DIP로 다형성을 적극적으로 활용하면, 모듈의 재사용성을 높일 수 있다.

    즉 DIP는 실체에 의존할 것인가, 추상화에 의존할 것인가에 대한 문제다.

    Ref https://black-jin0427.tistory.com/194


    이것저것

    • animation-fill-mode: forwards - CSS 애니메이션 실행 후 실행 마지막 상태로 남아있게 하는 법 (Ref)
    • Poc: Proof of concept - 새로운 프로젝트가 실제로 실현가능성이 있는지 효과와 효용, 기술적인 관점에서부터 검증하는 과정
    • aria-activedescendant - 여러 개의 focusable한 요소가 있을 때, 선택된 요소와 상관없이 어떤 요소에 포커스 되었는지 표시한다. (Ref)
    • webkit-tap-highlight-color - 비표준 CSS 속성으로, 모바일에서 <a> 태그 즉 링크를 터치했을 때 하이라이트를 표시한다. iOS와 안드로이드의 웹킷 기반 브라우저 (사파리, 크롬 등)가 대상이다. (Ref1, Ref2)
    • Linux Crontab을 사용해서 일정 주기마다 특정 작업을 반복적으로 실행하게 할 수 있다.
    • Nest.js는 monorepo 구조를 지원한다. (Ref)
    • tsconfig의 compilerOptions의 declaration은, 해당 모듈의 d.ts 파일을 생성할 것인지 여부를 가리킨다. (Ref)
    • node.js validation 도구 joi (Ref)

    기타

    Rust는 과연 C++ 킬러인가?

    C/C++이 다른 언어에 비해 갖고 있는 큰 단점은, include 구문을 갖고 있다는 것이다. 헤더파일의 include 구문 탓에, 소스파일 파싱에 O(n^2)의 시간복잡도를 가지게 된다. 반면 Rust는 소스파일 파싱에 O(n)의 시간복잡도를 가진다.

    C/C++의 또 다른 단점은, 지나친 전방선언(forward declaration)이다. Rust는 런타임 코드가 뒤섞이지 않는 언어이면서도, 전방선언이 불필요한 언어다.

    전방선언(forward declaration) 이란? 식별자를 정의하기 전에 식별자의 존재를 컴파일러에게 미리 알리는 방식이다. 헤더 포함 의존성을 최소화하기 위해 도입된 방식이다. Ref https://ju3un.github.io/c++-forward-declaration/

    또한 C언어의 매크로는 단순 문자열 대체를 해준다. 하지만 지나칠 정도로 문자열 대체를 지원하여, 때로는 불필요한 오버스펙일 수도 있다. Rust의 declarative macro는, BNF 문법을 사용해서 매크로 안에 들어가는 파라미터를 자유롭게 정의할 수 있다. 또 Rust의 procedural macro를 사용하여 컴파일 타임에 코드를 실행해볼 수 있다.

    BNF(Backus-Naur Form) 란? 프로그래밍 언어를 정의하기 위한 메타 언어로, 정규화 표현에 많이 사용한다.

    Copy
    <digit> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
    <hex_letter> ::= A | B | C | D | E | F
    <hex> ::= <digit> | <hex_letter>

    Ref https://perfectacle.github.io/2018/08/15/bnf/

    이에 더해 Rust는 클래스 상속 대신 traits라는 개념을 사용하며, Rust의 enum 또한 신박하다.

    하지만! 이런 Rust에게도 단점은 있다.

    뒷 이야기는 출처⬇️에서 계속…

    Ref https://docs.google.com/document/u/1/d/19zX4p3jJGnk-GnTeGz4BSh8XKnVR0fM8x3BY1A-GdD8/mobilebasic

    위젯 주도 개발

    • CSS 선택자의 충돌 방지를 위한 BEM
    • 컴포넌트 접근 방식 - UI 마크업(html)과 UI 로직(자바스크립트)의 조합
    • CSS 모듈
    • 효율적인 데이터 fetching을 위한 공통 부모 접근 방식
    • 상태 관리 접근 방식과 prop drilling
    • 재조명되는 단순한 접근 방식 - API wrapper 또는 인터셉터
      • GraphQL 클라이언트, RESTful API

    …의 역사를 거쳐 탄생한 위젯 주도 개발!

    모든 페이지를 자율적으로 작동하고 독립적인, 소위 위젯으로 분할한다.

    모든 위젯은 다음과 같은 기능을 담당한다.

    • 필요한 모든 데이터를 UI에 가져와서 제공
    • 필요한 경우 서버의 관련 데이터를 변경
    • UI에서 데이터 표현
    • 로딩 상태의 UI
    • (선택 사항) 오류 상태에 대한 UI

    이러한 접근 방식은 위젯이 의존하는 API 쿼리를 투명하게 만들며, 위젯을 쉽게 테스트할 수 있다.

    Ref https://medium.com/@yujso66/번역-위젯-주도-개발-b3e95b261c18

    비동기 요청의 응답 값 검증 - Schema Validation Layer

    일반적으로 axios를 사용하여 비동기 요청을 할 때, 응답 형식으로 제네릭을 사용한다.

    Copy
    export default async function fetchPosts() {
      const { data } = await axios.get<Post>(
        "https://jsonplaceholder.typicode.com/posts"
      );
      return data;
    }
    
    export type Post = {
      userId: number;
      id: number;
      title: string;
      body: string;
    };

    하지만 제네릭은 컴파일 타임에서 에러가 잡히지 않기 때문에, 런타임에서 예상치 못한 문제가 터질 수 있다!

    이때 필요한 것이 Schema Validation Layer다.

    Validation Layer의 요지는 두 계층 사이에서 오고가는 데이터를 검증하는 계층을 두는 것이다. npm엔 Schema Validation을 위한 패키지가 많이 있다. 여기서는 zod를 사용한다.

    Copy
    // schema/post.ts
    import axios from "axios";
    import { z } from "zod";
    
    export type Post = z.infer<typeof Post>;
    export const Post = z.object({
      userId: z.number(),
      id: z.number(),
      title: z.string(),
      body: z.string(),
    });
    
    export type Posts = z.infer<typeof Post>;
    export const Posts = z.array(Post);
    Copy
    // remotes/post.ts
    /* Type Inference: 
      function fetchPosts(): Promise<{
          userId: number;
          id: number;
          title: string;
          body: string;
      }[]>
    */
    export default async function fetchPosts() {
      const { data } = await axios.get(
        "https://jsonplaceholder.typicode.com/posts"
      );
    
      return Posts.parse(data);
    }

    만약 잘못된 Schema로 parse를 시도한다면, ZodError를 throw한다.

    Copy
    export default async function fetchPosts() {
      const { data } = await axios.get('https://jsonplaceholder.typicode.com/posts');
    
      + return Post.parse(data);
      - // return z.array(Post).parse(data);
    }

    zod에서 제공하는 메서드들을 사용하면 schema validation을 손쉽게 할 수 있다!

    Ref https://www.pumpkiinbell.com/blog/remote/scheme-validation-layer

    Jetbrains의 fleet

    Jetbrains 차세대 IDE인 fleet이 공개테스트 버전으로 풀렸다!

    가볍고, 똑똑하고, 유연한 에디터를 제공한다고 한다.

    Ref

    memlab

    페이스북에서 JavaScript 메모리 누수를 찾기위해 제작한 메모리 테스트 프레임워크

    Copy
    memlab run --scenario test.js

    위 명령어로 간단하게 내 코드를 검사해볼 수 있다! 편리…

    근데 자바스크립트에서 메모리 누수는 어떤 경우들에서 발생할까? 다음 코드를 보자.

    Copy
    var obj = {};
    console.log(obj);
    obj = null;

    objnull로 만들었음에도 불구하고 크롬에서는 obj에서 메모리 누수가 발생한다. 크롬은 출력된 객체에 대해서 내부 참조를 계속 가지고 있기 때문이다.

    코드 상에서 메모리 누수가 발생하진 않지만, 클라이언트 캐시나 virtualization이 되지 않는 무한 스크롤 등의 상황에서도 메모리 누수가 발생하는 경우가 있다.

    MemLab은 다음과 같은 순서로 작동한다.

    1. 브라우저에서 puppeteer를 사용하여 서비스를 탐색한다.
    2. 페이지를 이동하면서 자바스크립트 heap과 페이지에 할당된 객체들을 비교한다.
    3. 메모리 누수를 발견하고 정제한다.
    4. heap을 순회하며 각각의 누수된 객체에 대해 보관 흔적(retainer traces)을 생성한다. 이 보관 흔적은 GC 루트의 참조 체인이다.
    5. 보관 흔적을 클러스터링한다.
    6. 누수를 리포트한다.

    Ref

    Microsoft Designer

    이제 나같은 똥손💩도 디자인을 뚝딱뚝딱 만들어버릴 수 있다~!

    Ref https://designer.microsoft.com/

    tsc port 근황

    swc의 창시자 강동윤 님이 만드신 거구나..!

    Ref https://kdy1.dev/posts/2022/10/tsc-port-status


    마무리

    주 4일제 베타 체험판이 끝났다… 이제 연말까지 공휴일 없다. 그치만 난 휴가가 많이 남아서 괜찮다 ^0^

    pt는 세 번이나 방황한 끝에 드디어 결제했다..! 헬스장이 아니라 전문피티샵이라서 더 좋다. 트레이너 분도 넉살 닮으시고 첫 수업부터 왕 친근 ㅋㅋ 나같은 초짜를 잘 다룰 줄 아시는 것 같다. 이제 약골 탈출하고 지방은 불태워버리자아…

    라고 했는데 주말에 판교 idc 한 곳에 불이나서 카카오가 무려 15시간…? 넘게… 장애… 그리고 일요일 저녁인 지금까지도 일부 서비스들이 돌아오지 않았다. 카톡 뿐만 아니라 카카오맵, 페이, 택시, 바이크 등등 카카오 공화국이었던 대한민국은 완전 패닉에 빠져버렸고… 카카오 형들 힘내세요… 근데 처음으로 라인을 깔아봤는데, 꽤 괜찮은 것 같다. 이 참에 탈 카카오 했으면.. 싶지만 이미 아주 강력해져버린 Lock-in 🤷‍♀️

    그나저나 맥스🎧를 쓸지말지 아직도 고민중이다. 청음하고 더 고민되는 것 같다 ㅡㅡ 그린 왜 또 이뻐서…


    Relative Posts:

    10월 3주차 기록

    October 22, 2022

    10월 1주차 기록

    October 8, 2022

    zigsong

    지그의 개발 블로그

    RotateLinkImg-iconRotateLinkImg-iconRotateLinkImg-icon