2022년을 돌아보면 아쉽기도 하고, 그래도 나름의 성과도 있음에 약간의 만족을 하기도 하다.
2022년을 시작하며 내가 세 가지 길에 대한 고민을 했었다.
1. 타입스크립트를 깊게 파보고 nextjs를 해보고 프론트엔드 관련 공부를 계속할 것인가.
2. 러스트를 통한 웹 어셈블리, 차세대 웹 프레임워크를 배울 것인가.
3. 하스켈을 배우고 하스켈 프로그래머가 되고 싶다.
연말쯤 되서야 어느 정도 방향성을 정했다.
러스트를 이용한 프론트엔드 개발은 아직 좀 멀었다. (최근 주목받는, 내가 사용해보고 싶은 leptos는 아직 0.1 alpha이다.)
그러니 기존의 프론트엔드 개발을 하며 서서히 Rust 기반으로 넘어갈 것이며, 하스켈은 공부 목적으로 계속 공부를 하면서 서브 언어로 쓸 것이다.
Rust는 하스켈처럼 현대 수학적 이론도 언어에 다수 녹여냈다. 그러므로 하스켈을 익히며 익힌 개발화된 대수적 이론을 러스트에도 적용시킬 수 있는 것이 꽤 있을 것으로 예상된다.
1. fp-ts
퇴사하고 미친듯이 공부만 하고 싶었는데...
막상 퇴사하고 나니까 생각처럼 공부가 잘 되지는 않았다.
그렇지만 어느정도 성과는 얻은 게 fp-ts를 파고들어 실무에 약간 적용해볼 정도가 되었으며 haskell, fp-ts 등이 추구하던 대수적 관계와 다형성에 대해 약간의 감을 잡았다.
그리고 기존의 값 기반의 사고에서 타입과 다형성 기반의 사고를 좀 더 하게 되었달까...
특히 Task를 통한 예외 없는 Promise가 감명 깊었으며 (rust의 unwrap을 통해 Result를 받는 거랑 같다.) 이를 통해 피라미드 같은 사고 흐름을 플랫 하게 바꿀 수 있었다.
그리고 각 타입클래스의 Monoid를 가져와서 사용하는 것의 진의를 알게 되었다. 기존엔 이 개념이 왜 어려웠는지 모르겠다.
그저 ad hoc polymorphism을 이용해 Monoid라는 일괄적 형태로 제공하고 이를 받아 처리하는 거였는데..
map, chain, fold, ap, of 등등 기본적인 함수형에서 사용되는 개념을 한번 익히고 나면 많은 타입클래스에 적용할 수 있어서 처음에만 고생하면 그 이후에는 이해가 훨씬 쉬워진다.
lazy한 dependency injection도 신선한 충격이었다.
상태 기반의 패턴에서는 class에 의존하는 데이터를 주입 후 사용하지만 함수 기반에서는 해당 데이터가 있다는 것을 가정하고 함수를 작성한 후 lazy하게 의존성을 주입하는 개념이다
이 글이 내게 아주 큰 도움이 되었다...!
무엇보다 이런 형태를 이해하고 내가 직접 이 관계를 만들어서 사용할 수 있게 된 사고방식을 얻게 된 게 가장 큰 것 같다.
fp-ts는 현재 fp-ts/core, fp-ts/data, fp-ts/schema(기존의 io-ts 역할), fp-ts/optic(기존의 monocle-ts역할)로 새롭게 리뉴얼하며 개발 중이다. 이는 Effect-ts와의 통합과 더불어 구조를 바꾸려는 듯하다.
내가 썼던 fp-ts 관련 포스트
"typescript는 soundness한 언어를 지향하는게 아닌 javascript의 superset을 지향한다." 라는 메인테이너의 말에 적지 않게 실망했지만... sound-type 적으로 보안할만한 최고의 방법 중 하나는 fp-ts, effect-ts라고 생각합니다.
2. Side Projects (prisma, remix, chakra-ui, zod, tailwind)
2개의 사이드 프로젝트를 했었는데...
하나는 사실상 흐지부지 된 것 같고.. 나머지 하나는 시간 날 때 조금씩 작업 중이다.
둘 다 remix.run 을 사용해서 만들었다.
nextjs vs remix
나는 nextjs를 지금 회사 다니면서 사실상 처음 써봤다.(전 회사에서도 쓰긴 했지만 잘 알지도 못한 채 곁다리 작업 한 거라 쓴 걸로 안치겠다.)
확실하게 좋은 점은 주류 프레임워크라 정보가 참 많고 여기저기 지원이 안 되는 라이브러리가 없다.
하지만 진짜 답답한 것은 지금은 베타로 실행되고 있지만 appDir의 레이아웃 방식이 nextjs 12 버전 때는 없어서 remix로 nested layout방식으로 페이지를 구성하다가 nextjs를 쓰니까 답답해 죽을 맛이었다.
지금도 nextjs appDir 방식으로 개인 프로젝트를 하나 하는 게 있는데 아직은 비추한다. 여러 런타임 라이브러리에서 지원이 안되기 일쑤이며 정보도 없다.
그리고 올라온 이슈를 보면 라이브러리 개발자들도 appDir이 정식버전으로 되고 나서 수정하겠다는 글들이 많다.
그렇지만 appDir의 방식이 자리 잡게 되면 이것은 무승부라고 쳐도 될지 않을까 싶다.
그러나 하나 더 답답한 것은 remix는 react-router을 쓰며 따로 도큐먼트도 잘 작성되어 있고 훨씬 직관적이고 좋은데, nextjs의 라우트는 그렇지 않았다. 그리고 nextjs 서버단 클라이언트단 라우트가 동기적이지 않아 생기는 문제들도 겪었으며 뭘 하든 내 예상되로 되는 react-router가 훨신 좋다.
하지만 주류 프레임워크라는 것이 주는 장점이 어마무시하다.
그러므로 앞으로 당분간은 회사의 메인 격 프로젝트에서는 무조건 nextjs를 사용할 것이다.
개인 프로젝트나 사이드 프로젝트라면?
appDir이 정식 릴리즈 전까진 무조건 remix.
새로 시도를 해볼만한 개인 프로젝트면 astro를 써보고 싶다.
prisma
사이드 프로젝트를 디자이너랑 나랑 둘이서 하게 되어서 백엔드까지 내가 맡아서 작업을 해야 하는 상황이 되었다.
그런데 sql부터 해서 백엔드까지 다 익히기에는 넘어야 할 문턱이 너무 많지 않은가?
그래서 prisma를 도입해보았는데 아주 장단점이 확실하다.
장점으론 프론트엔드 개발자가 백엔드까지 쉽게 개발할 수 있다.
그리고 타입도 생성해줘서 타입 safety하게 하기 좋다.
이는 생산성이 몇 배나 올라가는 것이나 다름없다고 생각한다.
정말... 프론트엔드 혼자서 사이드프로젝트로 강추다 강추
단점으론 join까진 쉬운데 이를 통한 2차 데이터를 만들기 어렵다. 사실 2차 데이터는 서버에서 만들면 그만이지만 이를 통해 페이지네이션을 한다고 치면 곤란하다.
prisma 공식 slack에도 질문을 남겼는데.. 결국 이럴 때 방법은 prisma에서 지원하는 로우 쿼리 함수를 통해 SQL으로 작성하여하는 것이다. 그러나 SQL을 쉽게 작성할 수 있었으면 애초에 prisma를 썼겠는가. 또한 prisma 코드와 sql 코드 두 가지를 따로 관리해야 하는 것도 싫다.
그리고 속도가 TypeORM에 비해 빠르다곤 하지만 결국 이런 방식은 느릴 수밖에 없다.
또 제네레이트 되는 타입이 어마무시하게 많아서 중대형 애플리케이션이라면 타입 때문에 에디터에서 타입 자동완성을 하느라 에디터 속도가 현저히 느려져서 매우 빡친다..
본인의 경우 테이블이 20개 정도 되니까 느려지기 시작했다.
근데 이는 SQL문을 사용하지 않을 것이라면 생길 수밖에 없는 문제들이기도 하다.
typescript를 사용하여 DDD hexagon pattern을 예시로 작성한 이 레포에서도 속도 문제로 slonik 으로 바꾸었다.
그러므로 본인이 SQL문을 사용할 줄 알고 PostgreSQL을 사용하며 js, ts로 db를 조회하면서 대형 애플리케이션이라면 slonik을 추천하겠다.
chakra-ui vs tailwind
한 번은 chakra-ui, 또 다른 하나는 tailwind를 각각 처음 써보았고. 이로 인해 각각의 장단점을 알 수 있었다.
chakra-ui가 잘 만든 것은 맞으나 나만의 커스텀 테마를 통해 녹여내려면 은근 공수가 필요하다.
또한 컴포넌트를 커스터마이징 하려면 러닝커브가 있다.
물론 chakra-ui와 tailwind는 성격이 다르나 내 작업 방식상으론 디자이너가 따로 있는 경우엔 tailwind + headless 한 기능 라이브러리를 사용하는 게 좋았다.
그런데 headless-ui를 사용했지만 너무 ui가 없었고, 내가 나중에 사용할 방식으로 생각하는 조합은 tailwind + radix-ui다.
zag도 써봤는데 버그가 있더라. 아직 사용하기엔 약간 시기상조인 느낌이었다.
zod
정말... zod를 왜 이제야 썼는지 원망스럽다.
prisma + zod 조합으로 많이 사용하길래 쓰게 되었는데, zod schema를 정의함으로써 dto 같은 역할을 함과 동시에 타입 선언과 밸리데이션까지 할 수 있다.
백엔드가 typescript 기반이라면 밸리데이션을 각각 따로 작성할 필요 없이 zod를 통해서 통일할 수 있다.
그러면 백엔드 측에서 사용자 이름을 최대 8글자에서 6글자로 바꾼다면, 프론트에서도 코드 하나 수정 없이 해당 내용이 적용되게 할 수 있는 것이다.
그리고 data를 최종 형태로 변경하도록 하는 tranform을 추가할 수 있으므로 중간에 어뎁터 형식의 레이어를 낄 필요도 없다.
react form에서 가장 주류인 react-hook-form에도 zod resolver를 통해서 바로 호환되어 zod는 삶의 질이 올라가는 잇템이다.
그리고 추후에 설명할 zodios를 통하면 매번 fetch 할 때 하던 타입 선언하고, 데이터를 변경하고, 예외 처리하고 하는 수작업들을 일일이 할 필요가 없다.
로우 한 레벨에서는 속도가 아주 빠른 편은 아닌 것 같으니 typebox를 추천한다.
주류는 zod이므로 zod가 여기저기 가장 지원이 잘 되므로 일반적인 케이스에서는 zod를 쓸 것이다.
3. 지금 회사 (nextjs, prisma, chakra-ui, trpc, tinymce, zodios)
지금 다니는 회사는 정직원으로 들어간 것은 맞으나 애초에 들어갈 때부터 대표랑 길게 있기로 얘기한건 아니다.
너무나도 이제 시작하는 스타트업이라 중장기적인 계획을 짜기에 무리가 있기도 하고, 나도 어느 정도 다니다 목표로 하는 회사들에 지원해볼 생각이라 애초에 계약 기간을 길게 잡지 않았다.
그리고 업무 시간도 주 30으로 잡고 풀리모트 근무에 코어타임도 없어서 꽤나 나한테 유리한 조건이기도 했다.
좀 더 공부를 하고 싶었고 그러면서도 자금 사정이 쉽지 않아서.. 일을 하면서 공부를 하려고 한 게 있다.
첫 번째 프로젝트
회사 메인 프로덕트에 그 당시 이제 막 뜨던 remix를 쓰는 것은 위험 부담이 있으므로 잘 아는 remix보다 써보진 않았지만 주류로 쓰던 nextjs에 prisma를 썼다.
chakra-ui를 쓴 것은 좀 후회된다. postcss + tailwind 쓸걸..
nextjs-auth를 사용해서 oauth를 했는데 다음에는 iron-session을 가지고 직접 다 해보고 싶다.
어차피 범용적인 세션 관리를 하려면 iron-session을 쓰니깐 말이다.
structure
도메인 기반의 구조를 강하게 가져가서 router(end point), schema(zod를 기반으로 한), db, utils, constants를 도메인 내로 엮었다.
prisma를 사용해서 백엔드도 nextjs를 사용하므로 더욱 도메인 기반의 구조가 유용했다.
컴포넌트는 ui, layout, 그리고 단독으로 하나의 기능으로 쓰일 수 있는 덩어리 컴포넌트를 article, 단독으로 하나의 페이지로 쓸 수 있는 것을 contents로 구분하였다.
page에서는 contents 컴포넌트를 불러오는 형식이며, 이렇게 페이지를 contents로 빼니 하나의 페이지를 모달 같은 다른 형식으로 제공하는 것도 해당 모달에서 contents 컴포넌트를 포함하면 끝이다.
독단적인 기능을 article로 빼면 하나의 기능을 여러 contents에서 사용하기도 편하다. 공용 components 폴더에 다 넣게 되면 비대해지는데, 추후 appDir 구조를 따른다면 각 레이아웃 폴더를 ui단의 도메인처럼 활용할 수 있어서 더 context를 구분을 하기 쉬울 것으로 보인다.
trpc
백엔드 개발자가 없어서 사실상 백엔드 개발까지 했으며 nextjs에서 백 - 프론트 간에 데이터 전송을 쉽게 하는 방법을 찾아보다 trpc를 도입하게 되었다.
어차피 백엔드 로직도 내가 짜니까 trpc의 진가가 그대로 드러날 수 있었다.
trpc에 zod를 낌으로써 zod의 모든 장점을 가지며, 백 프론트 둘 다 코드를 짜기가 아주 간편해진다.
trpc를 쓰면 엄청난 시간을 절약할 수 있었다. (다만 nextjs 13의 appDir에서는 아직 쓰기 좀 난해한 감이 있다.)
trpc는 백 - 프론트의 연결을 마치 함수를 써서 데이터를 호출하 듯하며 react-query도 포함되어 있어 react-query의 장점들도 가져가며 SSR에서 최적화된 사용을 할 수 있도록 helper도 존재한다.
tinymce (aws s3 image upload)
wysiwyg를 알아보던 중 tinymce를 썼는데.. 좋긴 하다. 큰 변화 없이 쓰기에 참 좋다. 근데 얘를 통해 개발하는 방식이 확실히 옛날 방식의 나긴 한다. 유료로 제공하는 tinymce.cloud를 사용 안 한다면 assets 폴더에 관련 js파일과 플러그인, 스킨 js 파일들을 넣고 불러오는 방식.. 과거 jquery로 개발할 때의 추억이 새록새록이다.
이로 인해 개발상의 약간의 문제도 있었지만 기능이 다양하고 파워풀한 건 맞다. 다만 플러그인 하나하나를 커스터마이징하긴 어렵다..
tinymce에서 추가된 이미지 form data를 nextjs api handler에서 받아 multer을 통해 form data로부터 파일을 추출해서 aws sdk를 통해 업로드하는 것을 했다.
이게 주로 웹에 있는 정보들이 구 버전 정보들이 많고 최근의 예시들이 적어서 삽질을 수십 번 했다.. 결국엔 했으니 다행이다.
근데 분명 더 좋은 방법들이 있을 것 같다.
내가 할 땐 aws sdk가 2 버전이었는데 3 버전이 새로 나오면서 타입 지원이 더 잘 된다니깐 이제 좀 쉬울지도 모른다..
혹시 보시는 분이 form-data 이미지를 aws s3에 업로드하는 쉬운 방법을 알고 계시다면 댓글로 전수 부탁드립니다.
(_ _)
두 번째 프로젝트
두 번째 프로젝트를 함에 있어 첫 번째 프로젝트에서 공용으로 사용할 애들이 많으므로 turborepo를 사용하여 monorepo를 만들었다. (nx 쓸걸... 살짝 후회 중이다. 전통이 있는 만큼 자료들도 많다.)
기존의 유착 관계에 있는 것들이 내 생각보다 은근히 많았고, pnpm을 통해서 프로젝트의 루트에 패키지들을 관리하면서 기존의 런타임 패키지들 때문에 프로젝트의 nextjs.config.js에 webpack을 통한 설정을 이것저것 해주어야 했다.
prisma처럼 generate하고 런타임으로 실행하는 것은 나처럼 이로 인해 고생하는 사람들이 꽤나 있었다. 그래서 내 생각보다 모노레포로 바꾸는 게 힘들었다.
웬만한 프로젝트를 함에 있어서 규모가 어느 정도 있다면 모노레포로 시작하는 게 낫겠다 싶었다..
zodios
두 번째 프로젝트는 백엔드 개발자가 모노레포 안에 따로 nestjs로 프로젝트를 따로 진행하므로 기존의 trpc를 쓸 필요가 없었다.
그래서 백엔드랑 논의해 공통 모델을 zod로 작성하고 프론트에서 zodios로 데이터를 가져오도록 구조를 설계했다.
zodios와 관련된 글은 내가 따로 포스트를 했다.
4. ETC
새롭게 기존의 여러 테스트, 공부를 하던 프로젝트를 모노레포로 바꾸었다.
여기에서 나만의 코어 라이브러리를 만들고, 리엑트 라이브러리도 만들어보고 다양한 것을 테스트할 예정이다.
d3
최근 d3를 공부하고 있다.
공부하게 된 계기는... 그동안 수많은 고수준의 차트 라이브러리들을 사용해 봤지만 무언가... 다 조금씩 부족함이 있고 버그들이 있다. 여러 차트 라이브러리를 사용해본 사람은 공감할 것이다.
그리고 디자이너한테 이 차트 라이브러리를 사용하면 어디서 어디까지 커스텀이 가능하고 어떠한 기능을 추가할 수 있고... 이런 것들을 이해시키는 게 굉장히 어렵다.
디자이너한테 디자인 요소적인 제한을 두기도 싫다.
이 모든 것들이 쌓이고 쌓여서 결국 d3를 확실히 공부해서 웬만한 대부분의 차트를 구현해 낼 수 있는 역량이 프론트엔드 개발자로서 절실히 필요하다고 느꼈다.
그래서 공부하게 되었는데 생각 외로 쉽고 재밌다.
쉽다는 게 d3가 굉장히 저수준의 라이브러리일 줄 알았는데 매직과 슈거도 은근히 많으며 뭐 도형에 대한 기초적인 수학 공부를 다시 해나가는 것도 재미있었다.
이런 재미를 중 고등학생 때 느꼈으면 참 좋았으련만...
vanilla-extract
나만의 ui 라이브러리를 만들고 싶었다.
위에서 언급한 radix-ui와 zag의 headless-ui한 기능을 기반으로 vanilla-extract로 일반적인 패턴에 대한 스타일적 요소를 제네레이트 하거나 미리 구현해놓고 사용하는 식으로 말이다.
애플리케이션단에서는 tailwind가 생산성이 높아 주로 tailwind를 쓰겠지만 라이브러리단에서는 type safety하면서 스타일 제네레이트에 능한 vanilla-extract가 훨씬 적합해 보인다.
이와 더불어 컴포넌트를 점진적으로 구현해나가는 패턴을 사용하며 스타일적 요소와 병합하는 패턴을 좀 더 연구해볼 생각이다.
이번 년 초 퇴사하고 한동안 죽은 듯 공부하기로 다짐했었다.
하지만 내 생각처럼 공부를 하지 못해 스스로에게 실망을 하기도 했다.
내 안에 내가 이상적으로 생각하는 개발자의 능력을 가지려는 강박이 되려 나를 그로부터 회피하려 하게끔 방어기제를 펼치는 것일지도 모른다.
2022년을 마치며 돌아보면 어찌 됐건 퇴사하고 공부를 하고 새로운 프로젝트들을 함으로써 전 회사를 계속 다녔다면 배우기 힘들었을 만큼의 성과를 얻었다고 생각한다.
정들었던 동료들과 익숙하고 편했던 회사를 떠나 몇 번 후회를 하기도 했지만 삶에서의 변화들이 나에게 어떠한 시련을 주고 그것이 나를 돌아보게 만드는 것의 계기가 되었다.
내가 지금 겪는 감정, 심리적 요소들이 언제고 한 번쯤은 맞이했어야 할 내 안에 통합되지 못한 파편들이었다는 생각이 든다.
'개발' 카테고리의 다른 글
live template 작성 모음 (0) | 2022.02.16 |
---|---|
프론트 개발자, 직장인으로써 일하면서 느끼는 점들 (3) | 2021.04.21 |