# 2023 7월 TIL

# ✨ 7월 돌아보기

  1. 십자인대가 완전 파열됐다.
    • 수술 예후는 좋으나 회복 기간이 필요해 9월 중순까지는 재택하기로 했다.
    • 퇴원 후 2주는 혼자 밖에 나갈 엄두를 못내다가 7월 마지막 주차에 산책을 시작했다.
    • 십자인대 부상이 유독 힘든 이유가 '같은 일을 수행해줄 다른 인대나 근육이 없어서' 라고 한다.
    • 십자인대.. 트럭 팩터가 0이구나 너..
  2. 회사 신사업 무사 런칭
    • 쉽지 않았지만 어떻게든 해냈다. 다행이다.
    • 다음과 같은 선행 작업들이 설탭북스 프로젝트에 큰 도움이 되었다,
      • 개발 환경에서 사용할 수 있도록 MSW 도입
      • 스키마 퍼스트 개발에 관한 시도와 사전 논의
    • 관련해서 랩데이에서 발표할 기회가 생길.. 수도 있었는데 재택으로 어려워졌다. 아쉽.
    • 그래도 우디랑 신디랑 같이 뚝딱뚝딱 열심히 준비했다. 주제는 애자일하게 목표를 설정하는 방법
  3. React 공식문서 읽기 스터디 완주👏
    • react-docs (opens new window) 스터디 완주. 2달동안 개정된 리액트 공식 문서의 Learn 파트를 다 읽었다.
    • 매 회차의 분량이 적절해서 많은 이야기를 나눌 수 있었던 점이 좋았다.
    • 다양한 환경의 프론트 개발자들과 교류할 수 있었던 것도 좋았음 👏
    • 8월 한달은 좀 쉬고, 9월에 다시 모여 공식 문서의 Reference 파트를 같이 읽기로 했다. 기대중.
  4. 그 외, 개발면/업무면으로 시도한 작업
    • indexedDB 써보기
    • Nest.js 보면서 OOP와 RDB의 기본 개념에 대해 학습 (진행중)
    • web Worker 써봄 -> 모던 브라우저상에서 다중 작업 동기 처리가 필요한 경우 유용할지도?
    • storybook v7 찍먹 & play function 활용한 interaction test
    • 백오피스 릴리즈 사이클 정리 및 릴리즈 노트 양식 작성
    • 기타 등등.. 이번 달에도 많은 것을 했다.. 현 회사 입사 후 참 밀도 높은 한달 한달을 보내는 중.
      -> 지치지 않게 조심!
  5. 드뷔시 달빛 - 조성진 (opens new window)
    • 옛날에 엄청 좋아했는데 개인적인 이유로 잘 못 들었던 연주. 최근에 다시 들으니 그래도 좋더라.
    • 시간은 많은 것을 해결해준다.

# 2023.07.31

# 과거의 나와 싸우는 중

불과 몇 달 전에 짠 내 코드가 생각보다 너무 개차반이라 어이가 없다..
파일 업로드 로직에 얼기설기 끼워넣은 지역 상태를 추상화해서 전역 상태로 통합하는 작업 진행 중.
기준 없이 적어놓은 이상한 상태명도 뜯어고치고, 하는 김에 파편화된 비즈니스 로직도 묶어서 정리하고 있다.

-> 하지만 나는 이것도 계속해서 성장하고 있다는 증거라고 생각함.
그래서 기분이 나쁘지는 않다. 과거의 나보다 꾸준히 나아지는 중~

# 2023.07.27

# 담당 도메인 정기 릴리즈 사이클 확정

개발하는 짬짬이 숙원 사업(?) 해치우는 중.

  • WorkSpace(담당 도메인) 정기 릴리즈 사이클 정리 및 문서화
  • 정기 릴리즈 사이클 확정하고.. 기본적인 룰 정했음.
  • 제일 포인트는 '매 릴리즈는 최소 규모로 가져가며, 늘 이전 릴리즈로 롤백 가능한 상태를 유지한다.' 는 부분.
  • 개발 본부 이외의 실제 내부 사용자 공유용으로 릴리즈 노트도 만들어볼까나 룰루
  • 옛~날부터 정리하고 싶었던 부분이라 아주 즐겁고 속시원하다.

# 2023.07.24

# 커스텀 에러 객체를 활용한 FE 에러 핸들링

폴더 단위의 파일 업로드 로직 내에서 발생하는 에러를 핸들링하기 위해 커스텀 에러 객체를 만들어 사용

export type FileUploadErrorCauseType = {
  status: StatusType;
  filePath?: string;
};

/**
 * @description
 * 파일 업로드 로직에서 발생하는 에러를 status 기준으로 핸들링하기 위한 에러 클래스
 * @param message 에러 메시지
 * @param cause 에러의 status와 filePath 정보를 담고 있는 객체
 * @example
 * throw new FileUploadError('파일 업로드 중 에러가 발생했습니다.', { status: 'FILE_UPLOAD_ERROR', filePath: 'path/to/file' })
 */

export class FileUploadError extends Error {
  constructor(message: string, cause?: FileUploadErrorCauseType) {
    super(message);
    this.name = "FileUploadError";
    this.cause = cause;
  }
}

그리고 try catch

try {
  // ...
} catch (err) {
  // Promise.all으로 인해 err 값이 배열으로 들어오는 경우, 그 중 첫번째 err만 뽑아 처리한다.
  if (Array.isArray(err)) err = err[0];

  // 커스텀 에러인 FileUploadError를 catch하는 경우에 대한 분기처리
  if (err instanceof FileUploadError) {
    const { status, filePath } = err.cause as FileUploadErrorCauseType;

    switch (status) {
      case "WRONG_FOLDER":
        setStatus("WRONG_FOLDER");
        onToastError("문제가 된 파일 경로는 다음과 같습니다.", filePath);
        return;
      case "DUPLICATE_PAGE":
        setStatus("DUPLICATE_PAGE");
        return;
      default:
        setStatus("FAILED");
        onToastError("업로드에 실패했습니다.", String(err));
        return;
    }
  }

  // 그 외 통상 에러에 대한 분기처리
  setStatus("FAILED");
  onToastError("업로드에 실패했습니다.", String(err));
  return;
}

# SVG Stroke를 inset으로 사용하고 싶다면

  • 안타깝게도 HTML5의 SVG 태그는 stroke를 inset으로 변경하는 속성을 제공하지 않는다.
  • 하지만 stroke를 inset으로 사용해야 하는 경우는 발생하기 마련..
  • 그런 경우엔 이런 방법을 사용할 수 있다.
  • clipPath를 활용한 일종의 트릭
  • 레퍼런스: 스택 오버플로우 질문 (opens new window)
// AS-IS
import { SVGAttributes } from "react";

const MaskSvg = ({
  fill = "white",
  stroke = "black",
  ...props
}: SVGAttributes<SVGElement>) => {
  return (
    <svg
      width="100"
      height="100"
      viewBox="0 0 100 100"
      xmlns="http://www.w3.org/2000/svg"
      {...props}
    >
      <path
        id="path"
        fillRule="evenodd"
        clipRule="evenodd"
        d="M50 100C13.1946 100 0 86.8062 0 50C0 14.583 13.1946 0 50 0C86.8062 0 100 13.1946 100 50C100 86.8062 86.8062 100 50 100Z"
        fill={fill}
        stroke={stroke}
        strokeWidth={4}
        strokeDasharray="8 2"
      />
    </svg>
  );
};

export default MaskSvg;
// TO-BE
import { SVGAttributes } from "react";

const MaskSvg = ({
  fill = "white",
  stroke = "black",
  ...props
}: SVGAttributes<SVGElement>) => {
  return (
    <svg
      width="100"
      height="100"
      viewBox="0 0 100 100"
      xmlns="http://www.w3.org/2000/svg"
      {...props}
    >
      <defs>
        <path
          id="path"
          fillRule="evenodd"
          clipRule="evenodd"
          d="M50 100C13.1946 100 0 86.8062 0 50C0 14.583 13.1946 0 50 0C86.8062 0 100 13.1946 100 50C100 86.8062 86.8062 100 50 100Z"
          fill={fill}
          stroke={stroke}
          strokeWidth={4}
          strokeDasharray="8 2"
        />
        <clipPath id="clip">
          <use xlinkHref="#path" />
        </clipPath>
      </defs>
      <g>
        <use xlinkHref="#path" clipPath="url(#clip)" />
      </g>
    </svg>
  );
};

export default MaskSvg;

# 2023.07.14

# RDB의 Index란?

  • Index는 데이터베이스의 테이블에 대한 검색 성능을 향상시키기 위해 사용된다.
  • Index는 테이블의 컬럼을 색인화하여 검색 시 해당 컬럼의 값을 참조하여 검색 속도를 향상시킨다.

# Database Transaction이란?

  • 데이터베이스의 상태를 변화시키기 위해 수행하는 작업의 단위
  • 데이터베이스 시스템은 각각의 트랜잭션에 대해 원자성(Atomicity), 일관성(Consistency), 독립성(Isolation), 영구성(Durability)을 보장해야 한다. (이론적으로)
  • 하나의 Transaction은 하나의 논리적 기능을 수행하기 위한 작업들의 집합이다.
  • 하나의 Transaction은 Commit되거나 Rollback된다.
  • Commit : 하나의 Transaction이 성공적으로 끝났음을 알리는 것
  • Rollback : 하나의 Transaction이 비정상적으로 종료되어 이전 상태로 되돌리는 것

# 이런 것들을 갑자기 보는 이유

  • 브라우저에서 제공하는 비동기 저장소인 indexedDB를 활용하여 무언가를 하고싶기 때문
  • 개인 프로젝트로 작업중인 generator가 있는데, 유저가 입력한 데이터는 별도의 DB에 저장할 필요 없이 사용자의 로컬에만 귀속시켜도 된다.
  • 즉, 브라우저 저장소를 활용하여 사용자가 입력한 데이터를 일정한 규칙에 의하여 보존하기만 하면 됨.
  • 이 과정에서 blob 데이터까지 저장할 수 있는 브라우저 저장소가 필요했음..
  • 사실, 존재 자체는 알게된지 좀 되었는데요, 십자인대 파열로 입원한 김에 끼적끼적 공부하기 시작했습니다.
  • 기본적인 트랜잭션을 구현하는데까지는 성공했지만 이게 대체 뭔지 직관적으로만 알겠고 명확하게 이해되지 않아서 공부 start