Skip to main content

인포메이트 3주차 공유(협업)

· 14 min read

인포메이트 3주차 공유(협업) 모음입니다.

아니 Query Key가 무슨 호크룩스인가요? - 윤해진
CI/CD가 협업에 필요한 이유 - 김하나

아니 Query Key가 무슨 호크룩스인가요? - 윤해진

협업을 하면 무엇이 떠오르시나요?

다양한 것이 있겠지만 저는 코드 컨벤션과 같은 것이 우선적으로 생각이 났습니다.

사람들은 각자 가진 코드의 스타일이 있습니다. (개발 쪼라고 할 수도 있겠습니다.)

그러나 서로 각기 다른 스타일이 하나의 서비스의 구현에서 충돌한다면 이후 작업자 혹은 신규 작업자는 코드를 읽으며 혼돈에 빠지고 불필요한 시간을 들이게 될 것입니다.

따라서 저는 이번 협업이라는 주제에서 효율성과 일관성을 높일 수 있는 전략에 대해 공유해 보고자 하는 큰 틀을 생각했습니다.

tanstack query (react query v5)로 버전을 올리고 공식 문서와 TkDodo's blog를 읽으며 공부하던 중 이전부터 필요하다고 느꼈던 react query key의 효율적인 관리 방법을 소개하는 것을 보았습니다.

적절한 query key 관리 전략을 통해, 팀원 간의 코드 이해도를 높이고, 전체 프로젝트의 효율성과 유지 보수성을 향상에 중요한 역할을 할 수 있다 생각하여 세부적인 주제로 선택해 보았습니다.

React Query에서 Query key가 중요해요?

Query Key의 매주 중요한 부분은 QueryCache(쿼리 캐시)와 상호작용하기 때문일 것입니다.

라이브러리 내부적으로 올바른 데이터 캐싱을 가능하게 합니다.

또한, 상태로 존재하는 query key 값이 바뀌게 된다면 이는 리렌더링을 통해 React Query의 query key는 항상 변할 것이며 데이터를 다시 불러오게 됩니다. ⇒ (자동적인 상호작용이 일어나게 됩니다.)

그러나 때때로 우리는 수동적인 상호작용이 필요한 경우가 있을 것입니다.

query key가 가장 중요한 부분은 방금 언급한 캐시와 수동적으로 상호작용하는 경우입니다.

invalidate query와 같이 개발자가 수동적으로 쿼리를 조작하고자 할 경우에도 query key가 사용됩니다.

효율적인 React Query key가 필요한 이유?

앞서 이야기한 대로 react query를 이용할 때는 query key를 작성해 줘야 합니다.

그러나 query key의 경우 unique 한 값이어야 합니다.

또한, 때때로 우리는 mutation 이후 필요에 따라 query key를 무효화 시키고 싶을 수 있습니다.

그러기 위해선 고유한 쿼리키를 필요에 따라 invalidate로 무효화를 해주어야 합니다.

이렇게 우리는 key를 직접적으로 다루는 일이 꽤나 있습니다.

서비스가 보다 복잡해진다면 query 문과 key는 더더욱 많아져 초장에 잘 다듬어 놓지 않으면 마치 엉킨 실타래처럼 꼬이고 말 것입니다.

규칙 없이 선언된 key들은 어디에 위치하고 있는지 찾는 것에도 오래 걸릴뿐더러, invalidate를 통해서 무효화를 하려 해도 어느 곳에서는 다른 기준으로 선언된 key들로 의도한 대로 작동하지 않을 수 있습니다.

또한 unique 해야 하는 key가 겹친 채로 존재할 수도 있습니다. (위 경우들은 경험담입니다..)

이러한 이유로 시간을 버리는 것이 절대 좋은 경험은 아닐 것입니다.

따라서 저는 효율적으로 key를 관리할 수 있는 방법에 대해서 고민하게 되었습니다.

그렇다면 효율적이기 위해서 어떤 방법을 택했죠? : Query Key Factory

https://tkdodo.eu/blog/effective-react-query-keys

React Query 공부를 하던 중 마침 query key 관리법이 있어 읽어보게 되었습니다.

서비스의 확장에 따른 효과적인 keyFactory를 통해 키를 관리 전략을 소개하고 있었습니다.

간단하게 요약하자면, 공통의 부모 폴더에 **하나의 객체로 선언**하게 된다면 유지 보수 및 해당 query key 파악이 보다 효율적일 것입니다.

아래 코드와 같이 어떠한 기능과 관련된 query key들을 하나의 객체로 모아두었습니다

export const alarmKeys = {
list: ['alarm-list'] as const,
detail: (id: number) => [...alarmKeys.list, id] as const,
};

이렇게 된다면 유연하고 독립적으로 키에 접근이 가능할뿐더러 세부적인 key를 선언할 때 참고 및 변경이 용이합니다.

import { useMutation, useQueryClient } from '@tanstack/react-query';

import { postReadAlarm, postReadAllAlarm } from '@/apis/alarm';
import { alarmKeys } from '@/hooks/query/keyFactory/alarmKeys';

function useAlarmMutation() {
const queryClient = useQueryClient();

const readAlarm = useMutation({
mutationFn: postReadAlarm,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: alarmKeys.list });
},
});

const readAllAlarm = useMutation({
mutationFn: postReadAllAlarm,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: alarmKeys.list });
},
});

return { readAlarm, readAllAlarm };
}

export default useAlarmMutation;

위와 같은 방법으로 query key 관리가 이루어지니, key를 찾기 위해 여기저기 파일을 돌아다닐 필요도 없어졌을뿐더러, 새로운 키를 선언할 때에도 고민을 하거나 기존 key를 찾는 시간이 불필요해졌습니다.

+P.S

다른 방법 혹은 추천해 주실 방법이 있다면 댓글 등으로 공유해 주시면 감사하겠습니다!

읽어주셔서 감사합니다. 😁



CI/CD가 협업에 필요한 이유 - 김하나

협업 경험이 부족했을 때는 작업한 내용을 한 분기에 통합하고 해당 작업이 배포될 때까지의 파이프라인을 수동으로 검증해야 했던 기억이 있습니다.

그러나 Github Action이라는 CI/CD 툴을 통해 협업 경험을 개선하면서, 브랜치를 병합하기 전 CI에서 테스트를 수행하고 배포 과정(CD)을 자동화할 수 있게 되었습니다.

CI/CD 설명

CI/CD는 코드 변경 사항을 더 빠르고 안정적으로 제공하기 위해 빌드, 테스트 및 배포를 자동화하는 것을 의미합니다. 이는 지속적인 통합과 지속적인 배포로 이루어져 있으며, 각각의 정의는 다음과 같습니다.

  • CI - 공유 저장소내에서 코드 변경 사항에 대한 빌드 및 테스트를 통합한다.
  • CD - 변경 사항을 프로덕션 환경에 전달, 코드 변경 사항을 배포 자동화 한다.

따라서 CI/CD 파이프라인은 보통 두 가지 섹션으로 나뉘어 진행됩니다.

  • build →test → artifact / staging → production

CI/CD 의 자세한 워크플로우 예시는 여기를 참고하면 좋을 것 같습니다.

###CI/CD의 이점

Google DevOps 보고서에 따르면, CI/CD를 사용하는 조직은 다른 조직보다 배포를 208배 더 자주하고 리드 타임이 106배 더 빠르다고 합니다. 그 외의 이점으로는 다음과 같습니다.

  • 코드베이스가 언제든지 안정적인 상태 유지
  • 자동화되고 지속적인 테스트 가능 (비용 절감 효과)
  • 릴리스 속도 단축
  • 오류 격리, 장애 지점 감소
  • 오버헤드 비용 절감

###팀에 도입되고있는 cicd 현황

저희 트랙에서는 Github Actions를 이용하여 CI/CD를 실행하고 있습니다.

Github Actions는 특정 리포지토리에서 트리거 이벤트가 발생할 때 GitHub Action Runner에서 작업을 실행하는 구조입니다.

Runner 머신 구축 이후, 리포지토리 .github/workflows 디렉토리에 워크플로우 YAML 파일을 작성하기만 하면 별도의 설치나 세팅 없이 사용할 수 있습니다.

현재까지 정의된 워크플로우는 다음과 같습니다.

  1. Lint Check

코드 베이스의 안정성, 배포 과정에서의 에러를 최소화하기 위해 도입되었습니다. Pull Request가 등록되면 자동으로 eslint 테스트를 진행하고 eslint를 통과하지 못한 PR은 merge 하지 못하도록 제어됩니다.

  1. Type Check

마찬가지로 코드 베이스의 안정성, 배포 과정에서의 에러를 최소화하기 위해 도입되었습니다. TypeScript 파일에 대해 타입 검사를 수행하고, 코드에 오류가 없는지 확인합니다. 이또한 테스트에서 오류가 발생하면 merge 할 수 없습니다.

  1. Pick Reviewer

PR 리뷰어를 커스텀하기 위해 도입되었습니다. PR이 열리면 정해진 구성 안에서 랜덤으로 리뷰어가 배정되며, 이 과정은 슬랙으로 알림이 연동됩니다.

현재는 같은 도메인 팀 1명과 다른 도메인 팀 1명 구성으로 설정되어있습니다.

초기에는 PR Lint test 실행을 주목적으로 도입되었지만, 이 과정에서 Runner 머신 구축 뿐만 아니라 PR에 커밋이 추가될 때마다 중복 실행되거나, PR 본문이 변경되어도 린트 테스트가 실행되는 등 개선이 필요한 부분이 있었습니다.

따라서 Lint Test 이외의 개발 효율성을 높여줄 만 한 다양한 Action들을 찾았고, 검토해보면 좋을 것들을 모아봤습니다.

  • develop 브랜치에 코드 변경 사항이 merge되는 즉시 자동으로 젠킨스 빌드 트리거
  • 캐싱 데이터 활용하여 워크플로우 불필요한 작업 최적화
  • 사용하지 않는 코드 자동 레거시 체크

요약

  • CI/CD 전략은 소프트웨어 개발 라이프사이클 전반에서 효율성과 안정성을 증대시킵니다.
  • 저희 팀에서는 Lint Check를 위주로 사용하고있지만, 더 효율적인 프로세스를 도입할 수 있습니다.

References CI/CD(CI CD, 지속적 통합/지속적 배포): 개념, 툴, 구축, 차이CI/CD란?

https://resources.github.com/ci-cd/

https://www.martinfowler.com/articles/originalContinuousIntegration.html

https://it.donga.com/101955/

https://medium.com/naver-place-dev/github-actions를-활용한-개발-효율화-7df7a14b8843