8/28 TID : 흩날려라 천본이력서(예정) & grain 적용하기

그른손·2023년 8월 28일
0

오늘 뭘 하긴 했나요?


푸하하

10개 기업 지원과 중간 점검

이력서 멘토링 기간이 끝나고, 최종 과제로 10개 기업에 지원했습니다. 이력서는 원티드를 통해서 제출했구요.
가능하면 회사 홈페이지로 직접 지원하려고 했는데, 회사 홈페이지 지원 루트에서는 신입을 뽑지 않는다고 되어있거나, 회사 홈페이지에 지원공고가 없거나 등등 예외상황이 많았습니다.
그리고 어제 밤에 제출하고 오늘 아침에 4개 불합격이에요! 아마 나머지 6개도 내일, 모레 중으로 불합격 연락을 받아볼 수 있을 것 같습니다. 앞으로 한 5천번정도 떨어질 것 같은데 그 중에 첫 4번의 불합격이에요!

제가 지원한 기업들의 이름을 밝히기엔 아무래도 쪼끔 그렇고... 전체적인 기조만 적어두자면

  • React를 다룸 (Vue 등 제외...)
  • Typescript 요구
  • 문제 해결 능력과 커뮤니케이션 역량 요구
  • Redux, MobX 등 상태관리 패턴 구현 경험 요구

등의 공통점이 있었습니다. 이렇게 늘어놓고 보니 꽤나 당연하게 느껴지는 요구사항들인데요, 조금 주제넘게 말하면 '그나마 만만해보이는' 공고만 골라서 지원했어요. 리액트든 타입스크립트든 잘은 모르지만 다뤄본 경험은 있고, 상태관리도 어찌어찌 해봤고... Next.js를 요구하는 회사들이 생각보다 많아서 놀랐는데, 아예 접해본 적이 없는 프레임워크라 지원할 엄두가 안났습니다.

왜 서류탈락인가!

에 대한 분석이 필요한 시점이라고 생각합니다. 서류 탈락인 건 서류의 문제가 크겠죠... 이력서 멘토링을 받으면서 자기소개나 스택, 경험 등을 다듬어 작성하긴 했지만 기본적인 내용이 부실하면 좋은 이력서라고 할 수 없겠죠? 누워서 천장 보면서 생각해보니, 아마 이런 문제점들이 있지 않나 하는 생각입니다.

  • 자기소개의 부실함 (장점 어필 x) : 구구절절하게 쓰지 말래서 간단하게만 썼는데, 가뜩이나 내용도 없는 자기소개가 문장까지 간결하니 텅텅 빈 인상을 주지 않나 싶습니다... 제 장점은 뭘까요... 강점은 뭘까요...
  • 스택이 모자람 : 넥스트js도 없고 테일윈드도 없고 리액트쿼리도 없고... 또 필요한게 뭐가 있을까요? 아무튼 되게 허전한 스택들을 가지고 있습니다
  • 프로젝트 경험이 모자람 : 아마 이게 좀 큰 이유가 아닐까? 싶습니다. 지금은 참여한 프로젝트가 부트캠프 파이널 프로젝트랑 습작 수준의 토이프로젝트로 딱 두개밖에 없어서... 스택 란에서 쓸 줄 안다고 해놓았던 것들을 잘 쓰는 모습을 보여주기에도 모자란 것 같고, '그냥 시키는 것만 한 거 아니야?'라는 인상이에요. 그렇게 말씀하시면 할 말이 없는게 조금 분하네요..
  • 포트폴리오 없음 : 포트폴리오가 아직은 진짜 뼈대 단계라 첨부하기가 민망해서 이력서에 넣지도 않았습니다. 있으면 조금 달랐을까요?
  • 스펙? : 비전공자, 무경력 신입에 부트캠프 출신이고, 공모전 수상 경력도 없고, 스터디 등의 활동 경험도 없고... 쓰면서도 점점 자신이 작아지는 걸 느끼네요.

한 마디로 정리해보자면, '할 일 없어서 개발 배우겠다고 슬쩍 부트캠프 발 담궈놓고 이제 수료했으니 취직 되겠지? 하고 대충 지원 넣어본 멍청이' 티가 너무 나는 이력서라서 떨어진 것 같습니다.
총체적 난국입니다. 일단은 해야 할 일을 해야겠죠...

어쩌려구요?

  • 일단 프로젝트를 해야 해 : 포트폴리오든 토이프로젝트든 프로젝트 양을 늘려야 하고, 새 스택에 대한 공부도 병행해야 합니다. 리액트 쿼리랑 테일윈드를 더 공부해서 지금 만들고 있는 포트폴리오 프로젝트에 적용시켜봐야 할 것 같습니다.
  • 포트폴리오를 완성해야 해 : 무기는 많을 수록 좋으니까요! 다른 사람들 포트폴리오를 보면서 화려한 애니메이션에 압도돼서 구현보다는 css 배우는 거에 더 몰두해 있었는데, 일단은 때려치우고 내용부터 꽉꽉 채워야 할 것 같습니다. 반응형 정도만 신경쓰면서 만들어 보고, MVP를 구현한 이후에 애니메이션 등으로 화려하게 꾸며보는 게 더 좋겠습니다. 이렇게 멈춰 있으면 죽도 밥도 안될 것 같아요.
  • 스터디를 해야 해? : 기술면접 스터디든 독서 스터디든 뭐라도 하나 들어가야 할 것 같아요. 사실 이건 친구가 연초부터 꼭 하라고 했던 건데, 안했습니다. 반성은 하고 있습니다. (진짜임)
  • 더 바쁘게 살아야 해! : 예전부터 느낀 건데 이 분야를 공부하는 건 '죽을 것 같아야 비로소 한걸음' 인 것 같습니다. 지금은 너무 편하고, 나태하고 우울해져 있어요. 우울할 틈도 없을 때까지 몰아붙여야 합니다.

결국은 정신론이네요... 하지만 이런 케케묵은 정신론이라도 들먹여야 해결이 가능할 것 같은 상황입니다. 제 살 깎아먹으며 버틸 수 있는 시간이 얼마 남지 않았는데 할 일은 산더미처럼 많으니까요.
그래도 일기는 열심히 쓰네요 허허
내일은 좀 더 열심히 하겠습니다

내 포트폴리오 앱에 필름 그레인 효과 적용하기

정말 멋진 포트폴리오를 찾아서 레퍼런스 삼아 구현해보고 싶은 마음이 들었습니다. 완전히 표절하겠다는 건 아니고 (어차피 못함), 그 중에서 인상깊었던 부분 딱 하나만 따오려는 겁니다. 그게 웹 페이지 전체에 적용된 필름 그레인 효과였는데요, 왠지 모르겠는데 예쁘더라구요. 저는 큰 쓸모 없이 예쁜 걸 정말 좋아합니다.
해당 포트폴리오 구현 코드는 공개되어있지 않아서, 웹을 떠돌면서 필름그레인 효과를 구현할 수 있는 방법을 찾아봤습니다.

grained.js

grained.js라는 라이브러리가 있어서 다운받아서 이용해봤습니다.
그레인 효과를 여러가지로 커스터마이징할 수 있는 부분이 마음에 들었는데, 튜토리얼에 나와있는 대로 적용해보니 폰트, 이미지 등의 요소는 그레인이 적용되지 않고 배경에만 그레인이 적용된 채로 출력되는 게 아쉬웠습니다.

코드펜에서 주운 코드로 만들어보기

다른 라이브러리는 없나? 이걸 필요하다고 생각한 사람이 전 세계에 나뿐인가? 하면서 계속 찾아봤습니다. 아니더라구요. 코드펜에서 좋은 예시를 찾을 수 있었어요! js로 노이즈를 생성해서 캔버스에 띄우는 (솔직히 아직 잘 이해 안감) 식으로 필름 그레인을 구현할 수 있었는데, 노이즈 입자가 너무 굵어서 눈이 아프길래 함수 여기저기를 만져보면서 입자를 가늘게 수정해보았습니다.

const createNoise = () => {
        const idata = ctx.createImageData(wWidth, wHeight);
        const buffer32 = new Uint32Array(idata.data.buffer);
        const len = buffer32.length;

        for (let i = 0; i < len; i++) {
            if (Math.random() < 0.5) {
                buffer32[i] = 0xff000000;
            } //여기서 0.5를 0.1로 줄여줬어요! 뭐하는 부분인지는 솔직히 아직 잘 모르겠어요!
        }

        noiseData.push(idata);
    };

이렇게 바꾼 후에, 해당 코드를 react custom hook으로 바꿔서 useGrain이라는 훅을 만들어 보았습니다.

import { useEffect, useRef } from "react";

const createNoise = (
  ctx: CanvasRenderingContext2D,
  wWidth: number,
  wHeight: number
): ImageData => {
  const iData = ctx.createImageData(wWidth, wHeight);
  const buffer32 = new Uint32Array(iData.data.buffer);
  const len = buffer32.length;

  for (let i = 0; i < len; i++) {
    if (Math.random() < 0.1) {
      buffer32[i] = 0xff000000;
    }
  }

  return iData;
};

export const useGrain = () => {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  useEffect(() => {
    const canvas = canvasRef.current!;
    const ctx = canvas.getContext("2d")!;
    let noiseData: ImageData[] = [];
    let frame = 0;
    let loopTimeout: number;

    const paintNoise = () => {
      if (frame === 9) {
        frame = 0;
      } else {
        frame++;
      }
      ctx.putImageData(noiseData[frame], 0, 0);
    };

    const loop = () => {
      paintNoise();
      loopTimeout = window.setTimeout(() => {
        requestAnimationFrame(loop);
      }, 1000 / 25);
    };

    const setup = () => {
      const wWidth = window.innerWidth;
      const wHeight = window.innerHeight;
      canvas.width = wWidth;
      canvas.height = wHeight;

      noiseData = [];
      for (let i = 0; i < 10; i++) {
        noiseData.push(createNoise(ctx, wWidth, wHeight));
      }

      clearTimeout(loopTimeout);
      loop();
    };

    const handleResize = () => {
      clearTimeout(loopTimeout);
      setup();
    };

    setup();

    window.addEventListener("resize", handleResize);
    return () => {
      window.removeEventListener("resize", handleResize);
      clearTimeout(loopTimeout);
    };
  }, []);

  return canvasRef;
};

전문을 이렇게 길게 공유해도 되나 싶긴 하지만...
아무튼 App.tsx에서 아래와 같이 불러와서 연결해주었어요.

function App() {
  const canvasRef = useGrain();
  return (
    <>
      <canvas
        ref={canvasRef}
        className="absolute top-0 left-0 w-full h-full z-10 opacity-5 pointer-events-none"
      />
      <Routes>
      .
      .
      .
      </Routes>
    </>
  );
}

canvas의 css는 테일윈드로 바꿔주었구요. 이거 제가 코드를 다 이해하고 있어서 멋지게 설명해주면 되게 좋을텐데... 이게 어떤 방식으로 되는 건지는 아직 공부중입니다. 나중에 알게 되면 업데이트하겠습니다.

만들고나서

아무튼 두 가지를 테스트해보았습니다
1. App에다 canvas를 만들어두면 하위의 모든 루트에서도 적용이 되는지 => yes
2. 하위 루트 내에 canvas를 적용하면 상위 루트나 등위의 다른 루트에서는 적용이 되는지 => yes
3. 컴포넌트가 언마운트될 때 이벤트가 제거되는지 => yes

여기에서 테스트해보았고, Vite+React+Ts라는 동일한 환경에서 잘 작동하는 걸 확인한 후에 포트폴리오 앱에 적용했습니다! 여기서 볼 수 있어요

자세히 보지 않으면 그레인 효과가 잘 안보일 수도 있는데, 그게 더 예쁘다고 생각해서 보일듯 말듯 고운 입자로 적용했습니다.
뭐라도 하니까 좋네요! 다음엔 좀 더 쓸모있는 걸 해야겠어요

profile
프론트엔드 개발자

0개의 댓글