MementoAI 1개월 인턴 회고... "개발이 재밌다"

단단·2024년 11월 8일
10

글또

목록 보기
4/9
post-thumbnail

안녕하세요. 단단입니다.
10월 7일부터 11월 6일까지 1개월 인턴을 마쳤습니다.
입사했을 때 대표님께서 하셨던 말씀처럼
정말 3개월 같은 1개월을 보냈습니다.
그만큼 많이 배웠고, 부족한 점도 발견해 보완 중입니다.

기능 회고

제가 맡은 부분은 아래와 같습니다.
1. B2B 직원관리 사이트 중 회원관리, 회원상세(정보 입력) - 2주 + a
2. Mement.net 랜딩 페이지 - 1주
3. Mira-app 선택 티켓 기능 - 4일

B2B 직원관리 사이트

우선, 저는 공통 컴포넌트로 페이지네이션과 셀렉트 박스를 구현했습니다.

  • 페이지네이션
    처음에 상태(state)로 받아온 데이터를 관리하게 구현했지만, 그렇게 하면 리로딩 시 이전에 선택한 페이지가 아닌 1페이지로 돌아간다는 이슈가 있었습니다.
    그래서 쿼리 파라미터로 페이지네이션을 관리해 해당 이슈를 해결했습니다.
  • 셀렉트 박스
    Radix UI로 구현을 했는데, React-Hook-Form으로 폼을 관리할 것을 염두에 두지 않고 구현했더니 폼 관리하기 어려웠습니다.
    그래서 셀렉트 박스 자체가 ref를 받는 식으로 바꿨습니다.
const MemberInfoSelect = forwardRef<HTMLButtonElement, ISelectProps>(
  ({ content, value, onChange, style, placeholder }, ref) => {
    return (
      <Select.Root value={value?.toString() || placeholder} onValueChange={onChange}>
        <Select.Trigger
          className={`${style ? style : 'w-44'} relative justify-between text-black h-10 border-2 border-gray-300`}
          ref={ref}
        >
          <span>
             <span>
            {content.find((item) => item.id.toString() === value?.toString())?.name || placeholder}
          </span>
        </Select.Trigger>
        <Select.Content
          position="popper"
          className="max-h-[100px] overflow-auto w-[var(--radix-select-trigger-width)]"
        >
          <Select.Group>
            {content?.map(({ id, name }) => (
              <Select.Item key={id} value={id.toString()}>
                {name}
              </Select.Item>
            ))}
          </Select.Group>
        </Select.Content>
      </Select.Root>
    );
  }
);

공통 컴포넌트를 구현하면서 처음에 설계를 할 때 잘해야 동료들도 나도 편하게 사용할 수 있다는 것을 다시 한 번 깨달았습니다.
특히, 폼 관리에 쓰이는 공통 컴포넌트는 상태나 ref를 잘 받을 수 있게 구현해야 한다는 것을 기억하려고 합니다.

회원관리는 필터와 검색 기능 구현을 해야했고, 이를 쿼리 파라미터로 잘 받게 하는 게 관건이었습니다.

  • 파라미터 : /profiles/joy 처럼 일반적으로 파라미터는 특정 id나 이름을 가지고 조회할 때 사용합니다.
  • 쿼리 : /about?detail=true 처럼 쿼리의 경우엔 어떤 키워드를 검색하거나, 요청을 할 때 필요한 옵션을 전달할 때 사용합니다.

저는 location.search를 이용해 URL에서 쿼리 파라미터를 가져오고, 이를 new URLSearchParams()로 처리하여 쿼리 파라미터를 get했습니다.
URLSearchParams 객체에 queryParams.set()을 사용해 쿼리 파라미터를 갱신하며 회원정보 필터와 검색 기능을 구현했습니다.

const queryParams = new URLSearchParams(location.search);
const currentPage = parseInt(queryParams.get('page') || '1', 10);
const currentTab = queryParams.get('employment_status') || '전체';
const currentBranch = queryParams.get('branch_id') || '0';
const currentPart = queryParams.get('part_id') || '0';
const updatedSearchName = queryParams.get('name') || '';
const updatedSearchPhone = queryParams.get('phone') || '';

Mement.net 랜딩 페이지

Mira-app 장바구니 선택 티켓 기능

제 마지막 Task는 React Native로 구현된 Mira-app의 장바구니에 선택 티켓 기능을 추가하는 것이었습니다.
RN을 사용해본 적은 없지만, 배워보고 싶었던 프레임워크라 설렜습니다.

  • 초기세팅은 Xcode / CocoaPods / JDK / Watchman / 안드로이드 스튜디오 등을 설치하면 됩니다.
  • RN은 리액트 코드와 거의 비슷한데, UI 컴포넌트가 View, ScrollView, Touchable, Pressable 컴포넌트 등으로 나눠져있는 게 가장 큰 차이로 느껴졌습니다.
  • 간단한 터치 이벤트 등을 사용할 땐 Touchable 컴포넌트를 사용하고,
    복잡한 터치 상호작용이나 동적 스타일 변경이 필요할 땐 Pressable 컴포넌트가 적합하다고 합니다.

제가 구현해야 할 기능명세를 선임이 정리해서 보내주셨는데, 진짜 상세하게 참고 코드까지 알려주셔서 너무 감사하더라고요!
저도 나중에 인수인계를 하게 되면 저렇게 꼼꼼히 작성해야겠다는 생각이 들었습니다...ㅠㅠ

선임들 코드를 보며 새로 구현해본 방식은
overlay를 사용해 BottomModal을 제어하는 것이었습니다.

  • overlay로 Modal을 중앙에서 관리하면 다양한 컴포넌트에서 Modal을 호출해도 일관된 사용자 경험을 줄 수 있습니다.
  • overlay.open()을 await해 사용자가 모달을 닫을 때까지 이후 코드가 실행되지 않게 흐름을 비동기로 제어할 수 있다는 장점이 있습니다.
  const handleItemSelect = async (value?: string) => {
    if (!isVerified) {
      try {
        await overlay.open(
          <ConfirmModal
            overlayKey="first-booking-confirm"
            description={}
            resolve={() => {
              navigate('CustomerVerify');
              overlay.clear();
            }}
          />,
        );
        return;
      } catch {}
    }

    onChange(value || null);
  };

소감


위 이미지는 인턴 출근 전날에 다짐한 목표입니다.
이 다짐을 지금봐도 부끄럽지 않을 정도로 최선을 다한 한 달 이었습니다.
그리고 사실 동료와 경쟁을 했다기 보단, 매일 어제의 나와 치열하게 경쟁한 것 같습니다.

동료들 코드와 태도를 보면서 배운 게 많았습니다.
코드리뷰를 잘해주는 동료에겐 코드품질을 신경쓰는 태도를 배웠고, 풀리지 않는 문제를 함께 고민해주는 동료에겐 기술적인 배움을 얻기도 했습니다.
요구사항을 잘 파악하고, 이를 타인에게 잘 설명하는 동료의 소통 스킬, 늦은 시간에도 서버 이슈를 해결하는 동료의 책임감 등도 배웠습니다.
동기가 많으니 배운 것도 그만큼 많아 좋았습니다. 동기들 진심으로 감사합니다!

제가 짠 코드를 동료들이 잘 사용하지 못 할 때 스스로의 역량 부족을 실감하면서 힘들었습니다. 그러면서 동료가 쓰기 쉬운 코드를 짜고 싶은 마음이 크게 들었고, 이런 고민으로 리팩터링 2판도 읽고 있습니다.
저는 코드 품질과 개발 속도 둘 다 가져갈 수 있는 개발 고수가 되고 싶습니다. 포기하지 않으면 할 수 있겠죠.

아울러, 현업에서 PO, 기획자와 함께 일정에 맞춰 요구사항을 구현해본 경험이 정말 값진 것 같습니다.
그리고 제가 개발한 결과를 사용자에게 평가받는 게 보람있고, 기능을 일정에 맞춰 구현하기 위해 하는 야근에 스트레스를 안 받는 제 자신을 보며 다시 한 번 개발이 적성에 맞다는 것을 느낀 시간이었습니다.
저는 개발을 하면서 제가 원하는 대로 사이트가 동작하는 게 재밌고, 성취감이 들어 좋아요!

KPT 회고

KEEP

  • 기한을 준수해 요구사항에 맞춰 기능을 구현했습니다.

  • 새로 주어지는 challenge에 스트레스 받지 않고, 맡은 바에 최선을 다했습니다.

  • React-Query를 활용해 서버 상태관리를 했는데, 테이블별로 hook, API 요청 로직, 타입 정의를 모듈화하고, 쿼리 키를 객체화하는 방식을 제안해 유지보수성과 개발 생산성을 높였습니다.

  • 업무일지, 스크럼, 칸반보드 등을 적극 활용해 일정 관리에 힘썼습니다.

PROBLEM

  • 처음 코드를 짤 때 내 Task를 다른 동료가 이어서 진행할 것이라는 것을 고려하지 않았습니다.
  • BE에 질문과 요청을 할 때 구체적인 근거로 얘기하지 않았습니다.
  • 옵셔널 타입 사용과 불명확한 변수명으로 코드리뷰를 많이 받았습니다.

TRY

  • 협업을 할 때 내가 짠 코드를 타인이 이어 작업해도 잘 이해할 수 있게 설계하겠습니다.
  • BE에 질문을 할 때 페이로드와 요청 헤더를 함께 전달하고, 필요한 데이터 필드를 문서화해 정리하겠습니다.
  • 명확한 근거를 가지고 옵셔널 타입을 사용하고, 직관적인 변수명을 지으려고 노력하겠습니다.
profile
반드시 해내는 프론트엔드 개발자

12개의 댓글

comment-user-thumbnail
2024년 11월 9일

고생하셨습니다!!🙇🏻‍♀️
정말 읽으러 왔습니다ㅎ.ㅎ

1개의 답글
comment-user-thumbnail
2024년 11월 9일

고생했어 SI!
코드 보면서 많이 배웠고, 회고까지 잘 보고 갑니다~!

1개의 답글
comment-user-thumbnail
2024년 11월 11일

고생하셨습니다 ! 함께 일하면서 즐거웠고 많이 배울 수 있었어요 ㅎㅎ
일 하시는 것 만큼 회고도 알차고 깔끔하시네요 !

1개의 답글
comment-user-thumbnail
2024년 11월 15일

고생하셨습니다!! 점점 발전해나가시는 모습이 보이네요 멋집니다 👍

1개의 답글
comment-user-thumbnail
2024년 11월 17일

언제 어디서나 배움을 찾으시는 서인님 회고글을 보면서 역시 서인님은 정말 멋진 분이다 다시 한번 상기하게 되네요.

서인님께서는 인턴을 하시면서 정말 다양한 작업을 하셨던 거 같은데 늘 새로운 업무에도 빠르게 적응을 잘하시는 모습을 보고 정말 본받고 싶었습니다.

늘 문제에 대해서 객관적을 평가해주셔서 저는 덕분에 고민했던 부분에 대해 쉽게 해결할 수 있었어요.
도움 주셔서 정말 감사했습니다. 이제는 함께 일을 하진 못하지만 가끔 여러 문제에 대해 고민을 털어놓고 싶을 정도에요!!

다시 한번 감사해요❤️

1개의 답글
comment-user-thumbnail
2024년 11월 18일

고생 많으셨습니다 서인님! 같이 일 해보고 싶었는데 업무가 겹치는 부분이 없었어서 아쉬웠습니다ㅠ 다음에 더 좋은 기회로 봬요!!

1개의 답글

관련 채용 정보