# 2022년 12월 TIL
# 2022.12.29
# 2022 끝!
2022년 마지막 출근을 했다. 회사 내부 조직 구성 정돈을 위해 개발팀은 자회사로 소속을 이전하는 작업을 했는데, 이것을 위해 12/31자로 퇴사한다는 사직서를 작성했다. 이로서 2022년에 두 번 취직하고 두 번 퇴사한 사람이 되었음. 👀
# apollo mock server
apollo-server 4버전부터 mock server라는 것을 지원한다. 스키마와 기본적인 리졸버를 넣어놓으면 결과값을 난수로 반환해주는 형식. mock server 기본 세팅은 하나가 해주셔서 일단 필요한 스키마만 넣는 방식으로 작업해보고 있는데, 서버 개발과 앞단 개발이 필연적으로 병목될 수 밖에 없는 스타트업 조직 특성상 매우 유용하게 사용할 수 있는 기능이다.
다음과 같은 사항들이 유닛 단위에서 정의되었기 때문에 mock server를 사용할 수 있었다.
- schema first 개발 지향
- Graphql IDL을 통해 서버와 클라이언트가 정의된 schema를 공유
- github repository를 이용해 schema 버전 관리도 겸한다.
# 오늘 배운 키워드
- glob
- 의사난수
# 2022.12.21
# 일지
어느덧 입사 1개월차.. 시간 참 빠르다.
# storybook global css 설정
storybook에서 .css
로 되어있는 stylesheet를 global 영역에 적용하고 싶은 경우 preview.js
에 해당 파일을 import 하기만 하면 된다고 알려져 있다. 하지만 문제는 webpack5를 사용해서 번들링하는 경우 !!
현재 storybook의 기본 builder는 webpack4이기 때문에 node 18버전과의 호환성을 위해 webpack5 버전으로 올려서 사용하고 있는데, 이 경우 css 파일을 읽어올 수 있는 별도의 loader를 설정해주어야 한다.
// main.cjs
module.exports = {
// ...
core: {
builder: "@storybook/builder-webpack5",
},
webpackFinal: async (config) => {
const path = require("path");
// ...
config.module.rules.push({
test: /\.css$/i,
use: ["style-loader", "css-loader"],
include: path.resolve(__dirname, "../styles/"),
});
config.module.rules.push({
test: /\.(m?js)$/u,
type: "javascript/auto",
resolve: {
fullySpecified: false,
},
});
return config;
},
};
그리고 preview.js
에서 다음과 같은 방식으로 global css를 import해왔다.
import "../styles/globals.css";
그런데 다음과 같은 에러가 뜨는 것..
ERROR in ./node_modules/@storybook/builder-webpack5/node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[7].use[1]!./node_modules/style-loader/dist/cjs.js!./node_modules/css-loader/dist/cjs.js!./styles/globals.css undefined
Module build failed (from ./node_modules/@storybook/builder-webpack5/node_modules/css-loader/dist/cjs.js):
CssSyntaxError
(1:1) /Users/danny/Desktop/workspace.seoltab.com/styles/globals.css Unknown word
> 1 | var api = require("!../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js");
| ^
2 | var content = require("!!../node_modules/css-loader/dist/cjs.js!./globals.css");
preview.js
에 loader를 사용해 css 파일을 import 한다는 것을 다음과 같이 명시해주니 해결됐다.
(storybook에서 사용하는 경우에는 style-loader와 css-loader 패키지 설치는 따로 필요 없다.)
import "!style-loader!css-loader!../styles/globals.css";
# 2022.12.19
# apollo/client의 useLazyQuery
한 줄 요약
useLazyQuery를 이용한 데이터 fetching이 완료된 후에 특정한 동작을 수행하고 싶을 때에는 콜백을 값으로 받는 onComplete
옵션을 설정해주면 된다.
apollo/client의 useQuery 훅의 경우 복잡한 데이터 요청이 필요한 경우에는 잘 손이 가지 않는다. 데이터 페칭 시점을 조절할 수도 없고, 마운트 시점 중 정확하게 어느 타이밍에 요청이 들어가는지 파악하기 힘들기 때문인 듯. 뭔가, 요청 횟수와 시점을 명확하게 조절할 수 없다는 감각이 굉~장히 비효율적으로 느껴진다. 찝찝하다. 차라리 useLazyQuery나 useApolloClient를 활용해서 내가 원하는 시점에 깔끔하게 요청 날리고 말지.
게다가 다양한 option (opens new window)을 사용하면, 데이터 요청과 관련한 라이프 사이클 내에서는 원하는 동작을 거의 다 수행할 수 있다.
onComplete
: query가 에러 없이 success하게 끝났을 경우 해당 콜백 함수를 실행한다.onError
: 위와 반대. 한개 이상의 에러가 발생하는 경우 해당 콜백 함수를 실행한다. (errorPolicy
로ignore
가 가능하기 때문에 혹시 동작하지 않는 경우 해당 옵션 확인할 것)- 그 외에도
ssr
,client
,fetchPolicy
,pollInterval
등등..
언제나 그렇듯 자세한 내용은 공식 문서를 보는 것이 가장 정확하다.
// 예시 코드
const [searchBook, { data }] = useSearchBookLazyQuery();
// graphql-let을 이용해 각각의 gql에 대한 타입과 쿼리를 generate한 뒤 끌어와 사용하고 있다.
const callSearchBook = async (isbn: string) => {
await searchBook({
variables: {
input: {
target: BookSearchQueryTarget.Isbn, // generate된 ENUM 타입
query: isbn,
},
},
onCompleted: (data) => {
state.setBookInfo((prev: bookInfoType): bookInfoType => {
return {
...prev,
title: data?.searchBook?.title || "",
isbn: data?.searchBook?.isbn || "",
author: data?.searchBook?.authors || "",
publisher: data?.searchBook?.publisher || "",
thumbnail: data?.searchBook?.thumbnail || "",
};
});
},
});
if (!data) return;
return data?.searchBook;
};
# 2022.12.12
# vite 4.0.0
오늘의 교훈: 원인 모를 에러가 발생할 때에는 유관 라이브러리들의 버전도 체크하자.
오늘 있었던 vite 4버전 이슈처럼 3일 전에 새로운 버전이 릴리즈 되었을 수도 있다..
# 2022.12.08
# 2022 If.Kakao
Sentry 발표
- Sentry로 우아하게 프론트엔드 에러 추적하기 - 카카오페이 블로그 (opens new window)
- Sentry는 scope 기반으로 에러 데이터를 쌓는다.
- 데이터를 쌓는 것 뿐 아니라 그것을 검색할 수 있게 분류하는 것이 중요함. scope, tag, level 등을 활용해 설정할 수 있다.
- 유의미한 데이터만 수집할 수 있도록 필터링하는 것이 중요하다. tag, level 등의 기능은 이러한 목적을 위해 사용할 수 있는 일종의 수단이다.
- 서버와의 로그 분석 정합성을 높이는 것도 필요하다.
- 선언적 에러 처리 방법에 대한 고민과 그 과정, 결과물.
브런치 FE 심폐소생술
- 발표영상 (opens new window)
- 이거 재밌었다.
# 오늘의 일기
Q. 주니어/미들/시니어 개발자를 나누는 기준이 되는 요소는?
- 애쉬와 1on1을 하며 나누었던 이야기 중 개인적으로 기억하고 싶은 내용이 있어서 기록한다.
- 주니어와 미들을 가리는 기준은 무엇일까?
- 연차와는 무관하다. 그 사람이 어떠한 일을 할 수 있느냐에 주니어/미들/시니어의 여부가 달려있다고 생각한다.
- 일반적인 기준으로 보면, 개발 작업을 리드하여 진행할 수 있을 때 주니어 단계를 넘어 미들급으로 성장했다고 판단할 것.
- 애쉬는 주니어와 미들을 나누는 기준이 어떠한 기술 이슈에 대해 확신을 가지고 이야기할 수 있는지의 여부라고 생각한다고 했다. 그 이야기를 듣고 나도 '아하' 하는 깨달음이 왔음.
# 2022.12.06
# storybook에서 head 적용
.storybook/preview-head.html
파일을 생성- 해당 문서 내에 안에 넣고 싶은 태그를 입력
- Ref
# storybook global style 설정
.storybook/preview.js
내에 적용하고 싶은 style shett를 import- 상황에 따라 웹팩 builder 옵션을 설정해야 할 수 있음.
- Ref
# 요즘 하는 일
- 협업을 위하여 기존 에디터 프로덕트의 storybook 세팅을 하고 있다.
- 아토믹 패턴으로 구성된 기존 프로덕트 구조 및 컴포넌트 리팩토링을 진행하고 있다. 아토믹 패턴이 적절하지 않은 프로덕션이라는 판단이 들었고, 구성원들의 공감대가 형성되었고, 개발을 진행하며 리팩토링을 함께 진행할 수 있도록 병행할 수 있는 방안을 모색하는 중이다.
- 그래도 어느정도 가닥이 잡힌 듯! 어느 한가지 디자인 패턴으로 규정하지 않고 compound & composite 패턴을 혼합하여 사용하기로 했다.
- 파트원이 많지 않기 때문에 빠르게 소통하며 의사 결정을 진행할 수 있다는 점이 아주 좋다. 많이 배우며 공부하고 있는 하루하루다.
# 2022.12.04
# MongoDB와 데이터
- MongoDB와 같은 Document 기반의 NoSQL DB는 RDB처럼 엄격하게 데이터의 무결성을 보장하지는 않는다. 하지만 비정형 스키마 구조로 유연한 사용이 가능함.
- 단, 데이터 중복에 의해 데이터의 무결성 뿐 아니라 일관성이 저하될 가능성이 있음.
- 하지만 백엔드 개발 및 서버 개발시 이러한 부분을 잡아주는 것이 가능하다. 어디까지나 무결성과 일관성을 DB단에서 보장하지는 않는다는 의미일 뿐..
# 2022.12.02
# JS 전역 공간에 대하여
JS는 전역 상태를 생성하는 경우 Window(node 환경의 경우 Global)에 해당 값이 들어간다. 굉장히 기묘한 언어.. 즉, 전역 공간에 변수를 선언하는 경우 해당 변수는 광범위한 영역에 영향을 미치게 되며, 이로 인한 사이드 이펙트를 다 예상하고 대응하는 것은 불가능에 가깝다.
- 결론 : JS를 사용하는 경우 전역 공간은 최대한 사용하지 않는 것이 좋다!
절대 안 된다
라고 생각하는 것이 Best, - 이로부터 파생되는 내용인데, 코드를 짤 때 임시 변수도 최대한 제거하는 것이 좋다.
- 임시 변수란? 말 그대로 연산 등을 위하여 스코프 내에 임시로 생성한 변수.
- JS를 처음 배우면 필요한 연산을 수행한 뒤 임시 변수를 반환하는 형태의 함수 로직을 짜는 경우가 많다.
- 하지만 이러한 임시 변수의 사용은 코드를 읽기 힘들게 만든다. 즉 디버깅하기 어려운 코드가 되는 것.
- 게다가 명령형으로 가득한 로직이 된다. 아~주아주아주 안좋다.
- 그렇다면 그에 대한 해결책은?
- 함수를 최대한 구체화된 책임 단위로 작게 작게 나누는 것
- 함수의 결과값을 임시 변수를 거치지 않고 바로 반환하는 것
- 고차 함수를 사용하는 것
- 선언형 프로그래밍 등이 있다.