이번 주의 나는?

이번 주를 한 문장으로 표현하자면

계속 되는 의심의 주간이라 표현할 수 있겠다.

저번 주 계속해서 길어지는 회의를 마치고, FE, BE 모두 역할을 분담하여
작업에 들어갔는데, 생각한 것만큼 속도가 나지 않았고,
코드 또한 원활하게 작성되지 않는 느낌을 계속 받아왔다.
그러면서 계속 내가 배워온 시간을 의심하게 되고,
다른 사람과 비교하게 되는 건강하지 못한 시간을 보냈다고 생각된다.
하지만 지금 그만두면 2달이 넘는 시간 동안 아무것도 안한 것이 되어버리는
애매한 시점이기에 포기란 선택지는 허락되지 않는다.

팀 운영과 룰의 변경

Gitflow 전략 수정

1주 차 멘토링을 받으면서 나름 프로젝트를 잘 관리하고 있다는 생각이 부서졌다. 노션과 GitHub를 적절히 섞어 운영 중이라고 생각되었는데,
멘토님은 노션은 부가적인 요소이고,
최대한 많은 내용을 GitHub 내에서 남기길 권장하셨다.

그러면서 참고할 수 있는 전 기수분들의 Repsitorie를 보여주셨는데,
정리가 너무 잘 되어있어 놀랐었다.
배움에는 끝이 없다고 GitHub에는 아직 활용해 보지 못한 기능들이 무궁무진했다.

참고사항을 바탕으로 우리 팀의 Gitflow는 아래와 같이 수정했다.
✨ 기존의 노션에 있던 칸 반보드의 내용을 GitHub 프로젝트로 이전
✨ 기존 완료된 issue들을 상세히 작성
✨ 새로운 issue 발행 시에는

1. Project board에서 item을 생성
2. 생성한 아이템을 레포지와 연동하여 이슈화함
3. 생성된 이슈로 이동해서 브랜치 생성
    - features/ > 초기 기초 구현, 기능 구현 시
    - style/ > UI, CSS 작업 시
    - bug/ > 수정 시
    - refactoring/ > 코드 최적화 시
4. PR 생성 시 closes #이슈 번호 지정하여  
    해당 작업물을 머지 시 해당하는 이슈가 자동으로 닫히도록 설정(미구현)
5. Done으로 넘어간 것을 보며 흐-믓해 하기 

✨ Issues는 최대한 자세하게 기록하기
PR은 간소하게, 하지만 중요한 키워드는 담아주기
✨ close된 Issues 들도 최대한 태그 하면서 활용하기
✨ 서로에게 질문 등도 Board, Issues, PR에 남기며 최대한 많은 기록 남기기

위와 같은 룰을 만들어 한 주간 팀원들과 신경 쓰며, 열심히 관리한 결과

프로젝트 보드는 풍성해졌고, 가독성 또한 올라갔고,
코드에 관련된 부분은 모두 GitHub에서 보고,
관리할 수 있다는 이점을 얻을 수 있었다.

또한 최대한 현업에 가깝게 진행하기 위해서,
내 작업물에 대한 상세 내용을 적어서,
Issue만 보아도 팀원이 내가 작성한 코드를 이해하고,
공통 컴포넌트 등의 경우에는 바로 활용할 수 있도록 했다.

종합적으로 우리 팀은 게더라는 공간을 통해 실시간 소통이 가능하지만
GitHub 활용을 최대한으로 연습해 보는 방향으로
Gitflow 전략을 수정 및 적용해나가고 있다.

하루를 시작하는 룰

6주라는 짧다면 짧고, 길다면 긴 시간에서 벌써 2주 차하고도 3일이 지났다.
현재까지 프로젝트를 진행하면서 팀원 간 작은 잡음조차 발생한 적이 없는데,
함께 세운 룰을 성실히 지켜주는 팀원들에게 고마운 생각이 든다.
금주부터 새로운 룰을 추가했는데, 하루를 시작할 때 모두 모여 노션에
오늘의 목표를 추가하는 일이다.

아무리 바빠도 하루를 시작할 때는 모여 각자 목표를 지정하고,
화면 공유를 통해 서로 모든 팀원의 목표를 확인한다.

그 후 저녁 회의 시간에는 각자 설정한 목표를 얼마나 달성했는지 확인하고,
많이 달성한 사람이 있다면 그 팀원에게는 칭찬을 주고 스스로 자극받기도 하고,
고전하고 있어 당일 달성이 미미한 팀원에게는 모두가 격려를 해주는 방향으로
아침과 저녁의 끝을 꼭 함께 하고 있다.

자신이 오늘 한 일을 모두와 공유하는 것이 어찌 보면 껄끄러울 수도,
부담을 가질 수도 있지만
처음부터 터놓고 말할 수 있는 분위기가 형성된 것이
해당 룰이 잘 진행되고 있는데 큰 도움을 준 것으로 생각된다.

금주의 주요 코드

이번 프로젝트에서는 꼭 로그인/회원가입 기능 구현을 해봐야겠다고 결심하고 진행하는데..우선 변명부터 작성해 보자면…
React-query도 처음, TypeScript도 처음, 로그인/회원가입 구현도 처음…
이런 상태다 보니 초기 많은 헤메게 되었고 생각한 것만큼 진도가 나가지 않아
팀원들에게 미안한 마음이 들기도 하고 스스로에게 화도 나는 주간이었다.

그렇지만 끝내는 필요한 외부 API 설치도 모두 마치고,
정상적으로 기능이 동작하는 것까지 확인하니
마음이 한결 편해졌다. 99%의 고통과 1%의 기쁨으로
일한다는 말이 이해가 가는 대목이다.

사업자 등록번호 조회 API

const COMPANYNUM_VALID_KEY = process.env.REACT_APP_COMPANYNUM_VALID_KEY;

  const handleButtonClick = async () => {
    try {
      const response = await axios.post(
        `https://api.odcloud.kr/api/nts-businessman/v1/status?serviceKey=${COMPANYNUM_VALID_KEY}`,
        {
          b_no: [signInfo.companyNum],
        },
        {
          headers: {
            'Content-Type': 'application/json',
            Accept: 'application/json',
          },
        }
      );
      const data = response.data.data[0];
      if (data.b_stt_cd === '01' || data.b_stt_cd === '02' || data.b_stt_cd === '03') {
        setIsValid(true);
      } else {
        setIsValid(false);
      }
    } catch (error) {
      console.error(error);
      setIsValid(false);
    }
  };

기본 예제 코드도 나와 있기에 바로 사용하는 것이
어렵지 않을 것이라 생각되었지만,
역시 쉬운 것은 하나도 없다…
예제 코드를 현재 작업환경에 맞게 변경하며 코드를 작성하는 것은
생각보다 쉽지 않았다.

간략하게 설명을 붙여보자면

1. 국세청 오픈 API를 사용했다.
2. 활용 신청을 한 뒤 인증키를 발급 받았다.
3. 발급 키를 환경 변수에 할당하고, 안내받은 URI로 요청을 보내는데 이때,  
    body에 조회를 희망하는 값을 넣고, headers에는 type등의 정보를 넣어 보낸다.
4. 응답 데이터에서 각 숫자는 01(영업중), 02(휴업), 03(폐업)을 의미하는데  
    현재 코드상에서는 테스트용 사업자 등록번호가 폐업한 번호라  
    모두 ture로 처리되도록 설정한 상태이다.

실 서비스에서는 01, 02에 한해서만 인증을 통과시킬 예정이고,
테스팅 기간에는 무작위 숫자 10자리로 인증할 수 있게 할 예정이다.

Daum 우편번호 조회 API

이번 주 나를 가장 괴롭힌 코드이다.
어떠한 사이트에 가입할 때, 주소를 입력하는 것은 너무나 흔한 경험이고
그중에서도 KaKao 로고가 들어간 주소 검색 팝업창도 많이 봐왔었기 때문에
쉬울 것이라고 생각했다.. 그리고 아주 혼쭐이 나버렸다..

import React from 'react';

interface DaumAddressAPIProps {
  selectedAddressHandler: (postcode: string, roadAddress: string) => void;
}

const DaumAddressAPI: React.FC<DaumAddressAPIProps> = ({ selectedAddressHandler }) => {
  const postcodeRef = React.useRef<HTMLInputElement>(null);
  const roadAddressRef = React.useRef<HTMLInputElement>(null);
  const guideRef = React.useRef<HTMLSpanElement>(null);

  const searchAddressHandler = () => {
    new (window as any).daum.Postcode({
      oncomplete: (data: any) => {
        const roadAddr = data.roadAddress;
        let extraRoadAddr = '';

        if (data.bname !== '' && /[동|로|가]$/g.test(data.bname)) {
          extraRoadAddr += data.bname;
        }

        if (data.buildingName !== '' && data.apartment === 'Y') {
          extraRoadAddr +=
            extraRoadAddr !== '' ? ', ' + data.buildingName : data.buildingName;
        }

        if (extraRoadAddr !== '') {
          extraRoadAddr = ' (' + extraRoadAddr + ')';
        }

        if (postcodeRef.current && roadAddressRef.current) {
          postcodeRef.current.value = data.zonecode;
          roadAddressRef.current.value = roadAddr;
        }

        const guideTextBox = guideRef.current;

        if (guideTextBox) {
          if (data.autoRoadAddress) {
            const expRoadAddr = data.autoRoadAddress + extraRoadAddr;
            guideTextBox.innerHTML = '(예상 도로명 주소 : ' + expRoadAddr + ')';
            guideTextBox.style.display = 'block';
          } else if (data.autoJibunAddress) {
            const expJibunAddr = data.autoJibunAddress;
            guideTextBox.innerHTML = '(예상 지번 주소 : ' + expJibunAddr + ')';
            guideTextBox.style.display = 'block';
          } else {
            guideTextBox.innerHTML = '';
            guideTextBox.style.display = 'none';
          }
        }

        selectedAddressHandler(data.zonecode, roadAddr);
      },
    }).open();
  };

  return (
    <div>
      <input type="text" ref={postcodeRef} placeholder="우편번호" />
      <button type="button" onClick={searchAddressHandler}>
        우편번호 찾기
      </button>
      <br />
      <input type="text" ref={roadAddressRef} placeholder="도로명주소" />
      <span ref={guideRef} style=></span>
    </div>
  );
};

export default DaumAddressAPI;

라이브러리를 설치해 간편하게 하는 방법,
예제 코드를 참고하는 방법 이렇게 두 가지 선택지가 있었는데,
라이브러리를 사용했을 때는 팝업이 생성되는 것이 아닌
드롭 다운 형식으로 구현이 되어
맘에 들지 않아 새로 코드를 작성하면서 시간을 많이 허비했다..

위 코드의 해석은 아래와 같다.(GitHub Issue에 작성한 내용)

'AddressSearchAPIProps' 인터페이스의 'selectedAddressHandler' 함수는  
우편번호와 도로명 주소를 받습니다.

'DaumAddressAPI' 컴포넌트에서는 'postcodeRef', 'roadAddressRef', 'guideRef' 변수가   
React Ref 객체를 참조합니다.

'searchAddressHandler' 함수는 'daum.Postcode()' 생성자를 호출하여
우편번호 검색 API를 실행하며,
'oncomplete' 콜백 함수에서 검색된 주소 정보를 추출하여 각각
'postcodeRef.current.value', 'roadAddressRef.current.value', 'guideRef.current'   
변수에 할당합니다.

'DaumAddressAPI' 컴포넌트는 이렇게 할당된 변수들을 사용하여   
우편번호와 도로명주소 입력 필드 및 안내 메시지를 렌더링합니다. 

지금 보니 Issue에는 굉장히 딱딱하게 작성한 것 같다. 위 과정으로 선택된 우편번호와, 도로명주소는

const handleAddressSelected = (postcode: string, roadAddress: string) => {
    const fullAddress = `${postcode} ${roadAddress}`;
    setSignInfo(old => ({
      ...old,
      address: fullAddress,
    }));
  };

<DaumAddressAPI selectedAddressHandler={handleAddressSelected} />

가입 페이지에서 위 Handler를 통해 ‘fullAddress로 합쳐져
상태변수에 업데이트된다.

두 API 모두 한 번 어렵게 구현해 봤으니 다음에 어딘가에서 쓰일 때에는
간편하게 구현할 수 있겠다는 자신감도 충전할 수 있었다.

마무리

아쉽다!

  1. 회원가입 페이지를 구현하는데, 너무 많은 시간을 쏟은 것이
    다시 생각해 봐도 너무 아쉽다.
    조금 더 차분하게 코드를 작성했다면 달라졌을까 하는…
    생각이 떠나질 않지만 더 나은 다음 주를 만드는 것에 집중하려 한다.

  2. 또 다른 이들과 비교하면서 스스로를 괴롭혀
    마음속에 부정에 기름을 부어버린 점이 아쉽다.
    항해 진행 간 주기적으로 생기는 문제인데
    나는 나에게만 시선을 맞추는 마음가짐이 필요해 보인다.

  3. React-Qurey 숙련도가 부족하다고 느껴졌다.
    바쁘다는 핑계였을까, 아니면 새로운 것을 배우는 것에 꺼려 한 것일까
    간략하게 공부한 티가 코드를 작성하면서 느껴졌다.
    머릿속으로는 구상이 되지만 손으로는 코드가 나오지 않았다.
    일요일을 활용해 Query를 한 번 더 잡고 다음 주를 맞이할 계획이다.

그렇지만 잘했다!

  1. 아무리 멘탈이 부서져도 현실과 타협하며
    초기 기획한 기능을 줄이지 않고 맡은 부분을 끝내 구현했다!

  2. 팀원들과 함께 정한 룰을 성실히 이행하고,
    팀원들과 더 많이, 잘 소통할 방법을 모색한 점!

  3. 금주의 일요일을 최대한 활용한 점(진행중)

다음 주의 나는?

  1. 나를 프로젝트에 갈아 넣도록 하자,
    한 기능에서 딜레이 된 만큼 미구현된 기능들이 나를 기다리고 있다!

  2. 금일 공부한 Query를 잘 활용하여
    프로젝트에 진행 속도를 올려보도록 하자!

  3. TIL로 작성할 요소들을 잘 추리고, 작성하도록 하자!

카테고리:

업데이트:

댓글남기기