이 영역을 누르면 첫 페이지로 이동
천천히 꾸준히 조용히 블로그의 첫 페이지로 이동

천천히 꾸준히 조용히

페이지 맨 위로 올라가기

천천히 꾸준히 조용히

천천히 꾸준히 조용히.. i3months 블로그

PACK-UP v2.0 온보딩 - 세미나 발표

  • 2026.01.02 17:59
  • 💬 기록
반응형

 

 

 

 

소스코드 관리는 Git Flow 전략을 사용합니다.

main 브랜치에서 어느 정도 초기 기본 세팅이 완료되면 main 브랜치를 기반으로 dev 브랜치를 만들 예정입니다.

 

일감은 Notion 및 Jira로 관리됩니다.

자신이 맡은 일감 번호에 맞춰서, dev 브랜치로부터 feature/n 브랜치를 생성합니다.

 

feature/n 브랜치에서 작업이 완료했다면 feature/n 브랜치에서 dev 브랜치로 병합하는 PR을 요청합니다.

즉, dev 브랜치에는 PR 작업 단위 (일감 단위) 로 이력이 쌓이게 됩니다.

 

main 브랜치에는 정기적으로 병합해 시스템이 버그 없이 작동하는지 확인합니다.

 

 

 

 

 

먼저 원격 저장소를 로컬 저장소로 fork 뜹시다. 필요할 때 마다 Sync Fork 로 Update Branch를 실행해주세요.

 

앞으로 만들게 될 feature/n 브랜치는 로컬 저장소에만 만들어지고, PR을 통해 원격 저장소에 작업 내용을 반영합니다.

i3months/feature/n -> origin/dev PR을 만들고 병합합니다.

 

issue_template을 저장소에 만들어 둘 테니, PR 작성에 사용하세요.

 

 

 

 

 

팩업 ver1.0을 진행하면서 코드 컨벤션을 맞춰야 할 필요성을 느꼈습니다.

이렇게 PR 단위로 작업을 병합하게 되면, 병합하기 전 서로의 작업 내용을 확인할 수 있어 일관성을 유지하는데에 큰 도움이 됩니다.

다만, 다들 본업이 있으니 급하다면 다른 사람이 자신의 PR을 리뷰해 줄 때 까지 기다리지 말고, 본인이 직접 병합하고 작업을 이어가도록 합시다.

 

누군가는 월요일에 팩업을 달릴 수 있고, 또 다른 누군가는 월요일에 야근하고 수요일에 팩업을 달릴 수 있으니까요.

 

코드 리뷰를 기다리지 않더라도 이렇게 PR 단위로 작업하는건 의미가 있습니다.

이전 캡쳐에서 확인할 수 있듯, PR 단위로 프로젝트의 개발 이력이 남게 되어 이력 추적에 도움이 됩니다.

또한, 원격 저장소의 dev 브랜치에는 PR 단위로 커밋이 쌓이게 되어 브랜치를 깔끔하게 유지할 수 있습니다. 

 

 

 

 

Apps 는 독립적으로 실행되는 단위이고, Apps의 Modules는 재료가 되는 단위입니다.

core-domain 모듈 한 곳만 수정하면 api-core와 api-admin에 동시에 적용됩니다.

 

백엔드 먼저 보겠습니다.

 

core-domain

데이터베이스 구조와 핵심 규칙을 정의합니다.

여러 Apps에서 재사용 될 수 있는 Entity, Repository, Enums, 비즈니스 로직 등을 정의합니다.

 

core-auth

ver 1.0 에서 만들어둔 @Auth 애너테이션 등 JWT 관련 인증과 Spring Security Config를 정의합니다.

서버별로 다를 수 있으니 추상 클래스를 제공하는 형태로 활용하게 될 수도 있겠네요.

GlobalExceptionHandler도 여기서 정의하는게 좋아보입니다.

 

core-infra

외부 솔루션과의 통신을 담당하는 도구들을 정의합니다.

AWS S3, Redis, FCM, Elasticsearch, 결제 모듈, 지도 API 등..

 

settings.gradle에 저 모듈과 애플리케이션 구조를 정의해두고, 애플리케이션의 build.gradle에 dependencies로 모듈을 가져오도록 설정해줍시다.

 

프론트엔드도 마찬가지입니다.

 

api-client

백엔드 서버와 통신하는 모든 로직이 들어갑니다. 

axios, types/interface, interceptors 등 서버에 요청을 날릴 때 필요한 함수들을 정의합니다.

 

shared-utils

UI와 상관없는 순수 typescript 함수를 모아둡니다.

Formatter, Validators, Constants 등..

필요하다면 shared-hooks도 여기에 저장할 수 있겠네요. 

 

스프링에서 settings.gradle과 build.gradle을 사용했던 것 처럼, 리액트에서는 pnpm workspaces로 설정합니다.

프론트엔드 애플리케이션에서 공통 모듈을 의존성으로 추가하면 pnpm은 인터넷에서 다운로드 하는 대신 로컬 파일 경로를 보고 심볼릭 링크를 만듭니다.

 

pnpm-workspace.yaml 에 어떤 폴더를 워크스페이스로 관리할지 정의하고, 각 애플리케이션의 package.json에 공유 패키지를 가져다 쓰도록 설정해주도록 합시다. 

 

백엔드와 프론트엔드를 통합해서 하나의 리포지토리로 관리할지, 백엔드와 프론트엔드 따로 리포지토리를 관리할지는 고민이 필요합니다.

개발자 세 명이 모두 풀스택으로 개발하다 보니 하나의 리포지토리로 개발하는게 좀 더 좋아보입니다.

 

 

 

 

api-chat 서버를 개발할 때, 채팅 구현 관련 예제가 많은 node.js 기반의 express 프레임워크를 사용해보면 좋지 않을까 생각했었습니다.

다만, MonoRepo 구조를 도입하니 이 구조의 장점을 극대화하기 위해 서버는 모두 같은 기술스택을 사용하는게 좋아보입니다.

애초에 node로만 가능하고 스프링으로는 불가능한 구현이 있는 것도 아니니까요. 

채팅 내용을 저장할 때 NoSQL인 MongoDB를 사용해보는건 좋아보입니다. 관련해서는 같이 얘기를 나눠보면 좋겠습니다.

 

팩업 ver 1.0에서는 플러터로 모바일 앱을 개발했었죠. 이번에는 React Native로 기술 스택을 바꾸려 합니다.

어드민 페이지 개발은 리액트로 진행하는데, 모바일 앱 개발도 리액트 기반 기술을 사용하면 프론트엔드도 MonoRepo 구조로 개발할 수 있습니다.

 

 

 

백엔드 폴더 구조는 기본적으로 팩업 ver 1.0에서 설계한 그대로 유지하려 합니다.

다만, ver 2.0에서는 MonoRepo 구조를 사용하니 shared-module이 도입됐습니다.

이에 따라 서버단에서는 지울 수 있는 디렉토리가 있을 수 있죠.

 

파란색으로 밑줄 친 부분은 shared-module으로 따로 뺄 수 있어 보입니다.

 

현재 구조는 Domain Driven Development의 핵심 아이디어를 실무적으로 변형한 구조입니다.

지금보다 더 알아보기 쉽고, 눈에 잘 들어오는 구조가 있으면 언제든 말씀해주세요.

 

 

 

 

 

CQRS 패턴을 도입하는 것도 고려해 볼 만 하다고 생각합니다.

데이터의 변경과 조회를 분리하는 패턴입니다.

 

사실 Create Update Delete는 간단한 쿼리를 사용하고, Read에서 쿼리가 복잡해집니다.

그러니 Service와 Repository를 분리하고, 복잡한 Read 쿼리를 따로 분리해서 MyBatis나 QueryDSL을 깔끔하게 분리합니다.

 

Elasticsearch와 Redis, MongoDB를 적용한다면 CQRS 구조가 가져오는 이점이 더 커지겠네요.

 

 

 

 

 

React Native를 사용한 모바일 앱과 React를 사용한 백오피스 모두 FSD 아키텍처를 사용하는게 좋아보입니다.

혹시나 해당 아키텍처에 익숙하지 않은 분은 여기를 참고해주세요. 팀원들 모두가 아키텍처에 대해 알고 있어야 합니다.

 

MonoRepo 구조를 사용하기에 shared 부분은 좀 다르게 활용될 수도 있겠네요.

 

FSD 아키텍처의 여러 예시를 찾아봤을 때 파란색으로 표시한 entites, features, pages는 프로젝트마다 다르게 사용함을 확인했습니다.

그러니 좀 더 좋은 방식이 있다면 말씀해주세요. 

 

FSD 아키텍처를 기반으로 하되, 팩업에 가장 적합하고, 우리 팀이 이해하기 쉬운 아키텍처가 있다면 함께 토론하고 적용해봅시다.

 

 

 

 

이상적으로 서비스를 완성했을 때의 배포 아키텍처입니다.

 

서비스를 실제로 배포할 때는 AWS ECS를 사용합니다. 6개의 서버를 ECS환경에 배포합니다.

어드민 프론트와 모바일 앱은 ALB를 통해 서버에 접속합니다. 

 

채팅이나 푸시 알림 요청은 Redis를 경유해서 처리됩니다. 

투어를 등록할 때나 채팅에서 첨부파일이 있는 경우 Presigned URL 방식으로 S3에 업로드합니다. 

 

투어 검색 및 추천은 Elasticsearch를 사용하고, 채팅은 전용 NoSQL을 사용합니다.

 

 

 

 

마지막으로 프로젝트 진행 시 고려해야 할 점을 생각해봤습니다. 

 

여러 서버를 경유해서 트랜잭션이 유지되어야 하는데, 분산 트랜잭션을 어떻게 관리해야 할 지 생각해 봐야 합니다.

일감 관리는 어떻게 진행하는게 좋을까요? ver 1.0 에서는 노션을 사용했습니다. 좋은 방법이 있다면 공유해주세요.

Redis를 어떻게 사용해야 할까요? 우선 채팅 / 배치 / 푸시 서버에 대한 메세지 브로커로 활용할 예정입니다.

Elasticsearch를 도입한다면 투어 검색과 추천에서 활용할 수 있다고 생각했습니다. 어떻게 생각하시는지 알려주세요.

 

swagger.json 을 생성하고, openapi-generator, Orval 같은 도구를 사용해서 저 json을 읽고 Typescript 타입을 생성하는것도 좋아보입니다.

 

 

 

 

기획에 조금이라도 애매한 부분이 있거나, 개발하면서 조금이라도 애매한 부분이 있으면 바로바로 카톡방이나 디코방에 물어보도록 합시다.

기본으로 사용되는 ResponseEntity를 사용하기보다는 커스텀 객체를 만들어서 사용하는게 좋아보입니다.

 

 

 

 


 

 

관련 토론

 

1. MyBatis는 세션을 사용하는데, JPA는 EntityManager를 사용하니 DB가 커넥션 풀을 잡을 때 두 배로 잡을 수도 있을 것 같다.

 

2. 조회 쿼리는 JPA를 사용하지 않도록 강제하는것도 좋아보인다. MyBatis로만 처리하고, dto로 결과를 받아오자.

데이터베이스 부하는 SELECT 쿼리에서 발생하니까. Native Query로 최대한 컨트롤하자. LOCK 등.. 

 

3. CQRS 아키텍처의 필요성에는 동의하지만, 예제와 완전히 같은 방식으로 진행할 필요는 없어보인다.

서비스는 하나만 쓰고 리포지토리만 2개로 구분하는게 좋아보임.

 

4. Elasticsearch는 오버킬이지 않나? 우선 쿼리로 해결하고 나중에 고민해보자.

 

5. 커밋 메세지에 feat fix 다는거 너무 허례허식으로 느껴진다. 적당히 구분 가능한 형식으로 작성하는게 좋아보인다.

 

6. Squash and Merge와 Rebase and Merge 에 대해서는

사소한 규칙들이 개발 피로감을 더해주기에.. 최대한 간결하게 가는게 좋다고 생각함. 

Squash and Merge는 커밋 이력 볼 때 사람이 보기 편하니까 좋을 듯.. Rebase and Merge는 git bisect로 오류 커밋 추적이 쉽다.

우선은 Squash and Merge 쪽이 더 나아보인다. 

 

 

반응형
저작자표시 (새창열림)

'💬 기록' 카테고리의 다른 글

HOBBIT을 사용한 최적화 - 세미나 발표  (0) 2025.12.31
프론트엔드 아키텍처와 Feature-Sliced Design (2)  (0) 2025.12.02
[eziwiki] Static Site Genearator with Markdown  (0) 2025.11.28
Kakao Tech Campus 최종발표 - UniScope  (0) 2025.11.11
프론트엔드 아키텍처와 Feature-Sliced Design (1)  (1) 2025.08.31

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • HOBBIT을 사용한 최적화 - 세미나 발표

    HOBBIT을 사용한 최적화 - 세미나 발표

    2025.12.31
  • 프론트엔드 아키텍처와 Feature-Sliced Design (2)

    프론트엔드 아키텍처와 Feature-Sliced Design (2)

    2025.12.02
  • [eziwiki] Static Site Genearator with Markdown

    [eziwiki] Static Site Genearator with Markdown

    2025.11.28
  • Kakao Tech Campus 최종발표 - UniScope

    Kakao Tech Campus 최종발표 - UniScope

    2025.11.11
다른 글 더 둘러보기

정보

천천히 꾸준히 조용히 블로그의 첫 페이지로 이동

천천히 꾸준히 조용히

  • 천천히 꾸준히 조용히의 첫 페이지로 이동

검색

방문자

  • 전체 방문자
  • 오늘
  • 어제

카테고리

  • 분류 전체보기 (668) N
    • Algorithm (205)
      • Data Structure (5)
      • Theory && Tip (33)
      • Baekjoon (166)
      • ALGOSPOT (1)
    • Spring (123)
      • Spring (28)
      • Spring Web MVC (20)
      • Spring Database (14)
      • Spring Boot (6)
      • Spring 3.1 (11)
      • Spring Batch (6)
      • Spring Security (16)
      • JPA (12)
      • Spring Data JPA (5)
      • QueryDSL (4)
      • eGovFramework (1)
    • Programming Language (74)
      • C (25)
      • C++ (12)
      • Java (19)
      • JavaScript (15)
      • Python (1)
      • PHP (2)
    • Computer Science (142)
      • Machine Learning (38)
      • Operating System (18)
      • Computer Network (28)
      • System Programming (22)
      • Universial Programming Lang.. (8)
      • Computer Architecture (4)
      • Compiler Design (11)
      • Computer Security (13)
    • Database (21)
      • Database (7)
      • MySQL (3)
      • Oracle (3)
      • Redis (5)
      • Elasticsearch (3)
    • DevOps (20)
      • Docker && Kubernetes (8)
      • Jenkins (4)
      • Amazon Web Service (8)
    • Mobile (28)
      • Android (21)
      • Flutter (7)
    • 💡 솔루션 (16)
    • 👥 모각코 (6)
    • 💬 기록 (6) N
    • 📚 공부 (2)
    • -------------- (25)

최근 글

나의 외부 링크

메뉴

  • 홈
반응형

정보

i3months의 천천히 꾸준히 조용히

천천히 꾸준히 조용히

i3months

블로그 구독하기

  • 구독하기
  • RSS 피드

티스토리

  • 티스토리 홈
  • 이 블로그 관리하기
  • 글쓰기
Powered by Tistory / Kakao. Copyright © i3months.

티스토리툴바