Frontend/Weekly

ted는 서비스 프론트엔드 온보딩 프로세스에서 무엇을 느꼈을까?

YWTechIT 2023. 4. 3. 21:54
728x90

( 이 글은 사내에서 발표한 자료를 바탕으로 작성했습니다.  )

서론

안녕하세요! 5월 2일에 트리플 서비스 프론트엔드 팀에 합류한 ted입니다. 👋🏾 👋🏾

이번 아티클은 우리 TRIPLE의 기능 혹은 기술적인 문제를 깊게 파고들기보다 이제 막 회사에 적응하는 신규 입사자의 관점으로 온보딩 프로세스에서 느낀 점을 솔직하게 말씀드리려고 합니다.

본론

개발팀에서 단순히 개발을 잘하는 것도 중요하지만, 팀/동료와의 협업은 빼놓을 수가 없습니다. 트리플은 이를 위해 다양한 문화들이 마련되어있습니다.

1. 데일리 스크럼과 KPT 회고

소프트웨어 개발 방법론 중 하나인 애자일을 채택한 팀이면 빠질 수 없는 스크럼입니다. 우리 팀은 반복적인 개발(Sprint)기간을 2주로 잡고 있습니다. 월요일 격주로 스프린트 플래닝 시간을 가져 해당 주차의 스프린트 범위와 목표, 요구사항 분석 & 필요 작업을 산출하고 계획하는 작업을 진행합니다.

 

열심히 달리다 보면 어느덧 스프린트를 마무리하는 시점이 올 텐데, 이때는 그냥 넘기지 않고 스프린트 회고를 진행하면서 좋았던 점, 아쉬웠던 점, 개선하고 싶은 점에 대한 의견을 편안한 환경에서 자유롭게 얘기하여 다음 스프린트를 진행할 준비를 합니다. 그런데 회고시간을 빠르게 진행하다 보니까 자신의 의견을 구체적으로 전달하지 못하는 상황이 생겼습니다. 즉, 아쉬웠던 점이나 개선하고 싶은 점에 대해 자세히 들여다보는 시간을 갖기 어려운 문제가 있었습니다.

 

이러한 부분을 보완하기 위해 프론트엔드 팀에서 1주마다 진행하는 Weekly시간에 KPT 회고 방법론을 도입하자는 동료의 의견이 있었고 결론적으로 KPT 회고 방법론을 저희 팀에 도입하게 되었습니다. 이를 바탕으로 동료 간에 문제점에 대한 이해와 문제점을 개선하기 위한 다양한 의견을 통해 개인이나 팀에 성장에 도움을 줄 수 있을 것입니다.

 

이렇게 팀원들끼리 자주 소통하는 문화가 있는 덕분에 처음 입사하고 나서 팀원들의 궁금증과 고민을 알 수 있고, 반대로 내가 궁금한 점이 있으면 어렵지 않게 물어보고 도움을 얻을 수 있는 장점이 있습니다.

2. 지속적 통합과 자동화 배포 (feat. CI/CD)

지속적 통합(Continuous Integration) 은 빌드와 테스트를 자동화하여 지속적으로 SW 품질 관리를 적용하는 프로세스를 말하고, 지속적 배포(Continuous Deployment) 는 배포 자동화 과정을 통해 소프트웨어가 언제든지 신뢰 가능한 수준으로 출시될 수 있도록 보증하는 방법입니다.

 

CI/CD를 적용하면 개발이 얼마나 편해지는지 예시와 함께 살펴볼까요?? 간단한 문구를 수정하기 위해 main 브랜치에서 feature/test1 브랜치를 분기했다고 가정해보겠습니다.

 

compare-diff

 

수정사항을 한눈에 파악하기 위해 PR을 열고 수정이 끝나면 코드가 정상적으로 돌아가는지 직접 확인하기 위해 build테스트를 거치며 작성한 코드에 이상이 있는지 직접 눈으로 확인합니다. 만약, 변경사항이 짧다면 시간이 많이 소요되지 않겠지만, 변경사항이 많아지고 로직이 복잡해진다면 테스트하는 시간이 많이 소요되고 이 때문에 예정되었던 일정에 차질이 생길 수도 있겠죠..?

 

배포는 어떨까요? 위 사례에서 시간을 들여 검수까지 완벽하게 끝났다고 가정해봅시다. 다음 차례는 변경사항을 실제 서비스로 제공하고 있는 Prod 환경에도 배포해야 서비스를 이용하는 고객들이 변경사항을 알 수 있겠죠??

 

그래서 터미널의 SSHAWS에 연결하고, 내가 작업한 폴더를 복사해서 터미널에 붙여 넣고, 폴더 접근 권한을 재설정하고 Nginx를 재부팅하고, PM2도 재부팅하고, 배포 결과를 직접 Slack에 알려줘야 하고.. 어떤가요..? 매번 생기는 변경사항을 직접 배포한다고 생각하니 눈앞이 저절로 어두워지는데요..?

 

이를 해결하기 위해 트리플에서는 GitHub Actions를 통해 CI/CD를 진행하는 인프라를 구축했습니다. commit이 발생하면 Lint -> Test -> Build의 과정을 자동으로 Slack에 전송하고 CI 단계가 성공적으로 완료되면, 원하는 환경에 쉽게 배포 할 수 있습니다.

 

triple-trips-web-CI-image

 

ci-cd-slack-command

 

이처럼 CI/CD를 통해 자동화 단계를 거치게 되면 개발자가 직접 빌드와 테스트를 진행하지 않고, 자동으로 빌드와 테스트를 검증하여 결론적으로 소프트웨어의 질적 향상과 소프트웨어를 배포하는 데 걸리는 시간을 줄일 수 있습니다.

3. 맛있는 코드리뷰 시간

code-review-gif

 

PR을 열고 열심히 커밋하고나면 마음대로 merge할 수 없습니다. 왜냐하면 트리플의 저장소에는 CODE OWNER2~3명씩 할당되어있어서, 최소 1개 이상의 comment와 함께 APPROVE가 있어야 하거든요. 처음에는 코드리뷰가 왜 필요한지 잘 몰랐습니다. 그런데 코드리뷰를 통해 여러 팀원의 피드백을 듣고, 코드를 작성하니까 견문이 넓어진다는 느낌과 동시에 가독성이 좋아지는 느낌이 들었습니다. 간단하게 넘길 수 있는 부분도 코드리뷰를 통해 팀원이 읽기 좋은 코드로 작성하게 접근할 수 있고, 이렇게 작성한 코드는 이전에 작성했던 코드보다 실제로 더 효율적인 경우도 많이 있었습니다.

 

PR-comment

 

코드리뷰를 통해 느낀 점은 팀원 모두 개인 작업량이 할당되어있음에도 동료가 올린 PR에 최소 하나 이상의 코멘트를 남겨주실 정도로, 팀원에게 관심이 많고, 적극적인 피드백을 통해 코드를 양을 늘리기보다 품질을 향상하는 것을 중요하게 여기고 있다는 점을 느꼈습니다. 추가로 코드리뷰를 통해 고민하는 포인트는 다음과 같습니다.

 

  1. 해당 코드를 개선해야 하는지?
  2. 코드를 개선해야 한다면, 1부터 100까지 개선 방법을 모두 알려주기보다 키워드를 알려줌으로써 스스로 고민하고 개선 방법을 선택할 수 있게 하는지?
  3. 팀의 코드 스타일에 맞게 일관적으로 작성할 수 있도록 피드백을 주는지?

 

다음의 예시를 살펴볼까요? 뉴스레터 구독신청 페이지에서 Form을 만드는 코드를 작성하고 있었습니다. 하단의 코드블록을 대략 훑어볼까요?

export default function WithoutFormik() {
  const [{ userEmail, userName }, setInput] = useState<InputType>({
    userEmail: '',
    userName: '',
  })
  const [{ personalInfo, adInfo }, setAgree] = useState<AgreeType>({
    personalInfo: false,
    adInfo: false,
  })
  const handleInput = (e: SyntheticEvent) => {
    const { id, value } = e.target as HTMLInputElement
    setInput((prevState) => ({ ...prevState, [id]: value }))
  }
  const handlePartTerms = (e: { target: HTMLInputElement }) => {
    const { id } = e.target
    setAgree((prevState) => ({
      ...prevState,
      [id]: !prevState[id],
    }))
  }
  const handleTotalTerms = (e: { target: HTMLInputElement }) => {
    const { checked } = e.target
    setAgree(
      checked
        ? {
            personalInfo: true,
            adInfo: true,
          }
        : {
            personalInfo: false,
            adInfo: false,
          },
    )
  }
  const handleSubmit = async () => {
    await applyServer({
      userEmail,
      userName,
      personalInfo,
      adInfo,
    })
  }
  return (
    <>
      <Template />
    </>
  )
}

어떤가요?! 코드를 자세히 살펴보지 않더라도 코드가 매우 긴 것을 알 수 있습니다. 코드에 정답은 없지만 위 코드의 대략적인 문제점을 꼽아보자면 다음과 같은데요.

 

  1. 여러 개의 useState를 사용하여 중복되는 코드가 많다.
  2. input를 위한 handler 함수가 많아진다.(handleInput, handlePartTerms, handleTotalTerms, handleSubmit ...)
  3. 전체적으로 코드가 길고 가독성이 떨어지는 느낌을 받는다.

코드리뷰를 통해 결론적으로 Form을 다룰 때 FormikYup 라이브러리가 도움된다는 코멘트를 보고 코드를 작성했습니다.

 

newsletter-code-review
export default function WithFormik() {
  const {
    values,
    errors,
    isValid,
    isSubmitting,
    setValues,
    handleChange,
    handleSubmit,
  } = useFormik({
    initialValues: {
      userEmail: '',
      userName: '',
      personalInfo: false,
      adInfo: false,
    },
    validationSchema: Yup.object({
      userEmail: Yup.string()
        .email('이메일 형식이 아닙니다.')
        .required('이메일을 입력해 주세요.'),
      userName: Yup.string().required('닉네임을 입력해 주세요.'),
      personalInfo: Yup.bool().isTrue('개인정보 수집에 동의해주세요.'),
      adInfo: Yup.bool().isTrue('광고성 정보 수신에 동의해주세요.'),
    }),
    onSubmit: async ({ email, nickname, personalInfo, adInfo }) => {
      await applyServer({
        email,
        nickname,
        personalInfo,
        adInfo,
      })
    },
  })
  const { userEmail, userName, personalInfo, adInfo } = values
  const isActive = isValid && !isSubmitting
  const allTermsHandleChange = () => {
    void setValues(
      checkedAllTerms
        ? {
            userEmail,
            userName,
            personalInfo: false,
            adInfo: false,
          }
        : {
            userEmail,
            userName,
            personalInfo: true,
            adInfo: true,
          },
    )
  }
  return (
    <>
      <Template />
    </>
  )
}

상단의 코드를 보고 어떤 느낌을 받았나요? 전체적으로 코드의 길이가 많이 줄어들고 가독성이 좋아졌나요?! 이외에도 효율적인 부분들을 챙길 수 있었습니다.

 

  1. useState 대신 필요한 initialState로 필요한만큼 선언 가능
  2. input을 관리하는 handler함수를 따로 정의하지 않아도 된다.(라이브러리 자체 제공)
  3. 유효성(Validation)검사도 사용 가능하다.
  4. Form 관련 코드를 한 곳에 배치하여 코드를 일관적으로 작성할 수 있다.
  5. 전체적으로 코드가 짧아지고 가독성이 올라갔다.
728x90

4. Frontend Weekly

트리플에 들어오고 싶었던 이유 중 하나가 바로 Weekly 문화인데요, 트리플은 개발만 하는 것이 아니라 최근 유행하는 이슈, 트리플 도메인에서 궁금한 부분, 기타 공유하고 싶은 지식 등의 내용을 순서를 정해 매주 목요일마다 자유롭게 발표하고, 발표한 주제를 토대로 팀원들과 의견을 나누는 문화를 가지고 있습니다.

 

Weekly 문화를 좋아한 이유는 한정된 주제의 글만 있는 것이 아니기 때문인데요. create-triple-app 개발하기, Rest API가 가고 GraphQL이 왔다., i18n 국제화 처리, GitHub Actions 살펴보기, 장애 대응 프로세스 소개 및 Sentry 이슈 관련 논의, 혼자보다 둘이 작업하는 페어 프로그래밍을 해볼까?, 오픈 소스 기여하기 등등의 다양한 주제로 약 50개가 넘는 글이 올라와 있습니다.

 

트리플에 입사 후 사수에게 배우기만 했다면, 반대로 Weekly 발표를 통해 사수가 되어 동료를 가르쳐주는 시간을 가진다면 이 또한 색다른 경험이지 않을까 생각합니다.

 

여기서 발표한 내용을 토대로 나중에 국내 컨퍼런스(FECONF 2022) 혹은 국외 컨퍼런스(dev.events)에 나갈 기회가 생긴다면.. 생각만 해도 짜릿한데요?! 🚀

5. 시니어 개발자와의 1-on-1

처음 입사하고 나면 모든 부분이 생소할 텐데요. 당장은 개발에만 집중할 수 있어도, 문득 미래에 내 개발 커리어를 어떻게 쌓아야 할지와 같은 궁금증이 생길 수도 있고, 동료에게 쉽게 말할 수 없는 개인적인 질문이 생길 수도 있죠. 프론트엔드팀에서는 이러한 개발자 니즈를 고려하여 한 달에 한 번씩 1-on-1하는 시간을 갖고 있습니다. 이 시간을 통해 평소 궁금했던 개발 트렌드, 커리어, 개발에 임하는 자세, 협업방법 등을 물어보면 친절하고 자세하게 답변해주셔서 함께 일하고 싶은 개발자로 성장하기에 안성맞춤이라고 생각했습니다.

결론

지금까지 서비스 프론트엔드팀에서 겪었던 온보딩 프로세스를 간략하게 살펴봤는데요. 온보딩 프로세스를 통해 느낀 점은 신규 입사자가 회사에 잘 적응 할 수 있도록 도와주고 배려해주는 점이었습니다.

 

처음 출근할 당시 이것저것 궁금한 내용이 생길 때마다 질문을 너무 많이 해서 싫어하는 건 아닌지 고민을 많이 했었는데요. 궁금한 점이 생기기 전에 먼저 알려주고, 오히려 질문을 권장하는 문화가 있었기에 서비스 프론트엔드에 잘 적응 할 수 있는 계기가 되지 않았나 생각합니다.

팀에 잘 스며들 수 있도록 도와주신 팀 동료분에게 감사의 말씀을 전하며 이만 글을 마치겠습니다. 긴 글 읽어주셔서 감사합니다. 🙇🏾‍♂️ 🙇🏾‍♂️

 

thank-you-gif
반응형