한화시스템 BE15 백엔드 링크업 프로젝트 회고

박성용·2025년 4월 20일

프로젝트 회고

목록 보기
3/4

프로젝트 회고

1. 프로젝트 개요

이번 프로젝트에서 가장 큰 도움이 되었던 세 가지는 DDD 설계, 테이블 정의서, 테스트 케이스 정의서였습니다.

물론 이 모든 것이 유의미하려면 그 기반이 되는 요구사항 명세서와 ERD가 견고해야 합지만 그 위에 구조적 설계를 문서화한 이 세 요소는 실제 개발 단계에서 협업 효율성과 방향성 유지에 결정적인 역할을 했습니다.

DDD 설계서

처음엔 ‘도메인 주도 설계(DDD)’ 문서를 왜 작성해야 하는지 감조차 잡히지 않았습니다.

하지만 프로젝트를 마친 지금은 DDD 없이 이 프로젝트를 완성하는 것은 불가능했을 것이라 확신합니다.

저희 프로젝트는 총 37개의 테이블을 설계했고 이 모든 테이블이 각 기능에서 동일하게 쓰이지는 않았습니다.

결국 중요한 것은 각 테이블이 어떤 '맥락(Context)'에서 필요하고 사용되는가를 파악하는 것이었습니다.

이 과정을 통해 자연스럽게 도출된 각 '맥락'은 곧 하나의 도메인이 되었고 각 도메인은 프로젝트 소스의 최상위 디렉토리로 구성되었습니다.

DDD 설계를 통해 얻은 이점을 정리해보자면

  • 각 도메인은 응집력 있는 내부 구조를 가지며
  • 도메인 간 의존성을 최소화할 수 있었고
  • 추후 MSA로의 분리를 고려할 때 독립적 서비스 분리 기준이 명확해졌습니다

만약 이 과정을 거치지 않았다면, 도메인 간 의존성이 얽히고설켜 MSA 전환은 거의 불가능했을 것입니다.

따라서 DDD는 단순한 설계 도구가 아닌 시스템 구조를 올바르게 분해하고 설계하는 핵심 절차임을 이번 프로젝트를 통해 알게되었고 앞으로 이번에 배운 도메인 설계를 더 탄탄하게 학습하여 완벽한 수준의 도메인 설계란 무엇인지에 대해 학습할 것입니다.

테이블 정의서

처음에는 엑셀로 테이블 정의서를 작성하고, 여기에 스크립트까지 정리하는 일이 매우 번거롭게 느껴졌습니다.

그런데 한 번 정리해두고 나니 이보다 명확한 협업 도구는 없었습니다.

테이블 정의서를 작성하면서 내가 맡은 테이블의 구조에 대해 더 깊게 고민해볼 수 있고 내가 맡은 테이블 구조와 변경 사항도 한눈에 확인 할 수 있고 DDL 스크립트도 실시간으로 관리할 수 있었으며 다른 팀원이 수정 내용을 반영할 때 “그 테이블 스크립트 바꿨어” 한마디면 DDL을 손쉽게 수정할 수 있어 DDL을 처음 구성하는 것은 어려웠지만 관리하는 것은 어렵지 않았습니다.

물론 DB를 공유할 수 있는 상황이라면 이러한 작업은 필요하지 않겠지만 DB를 공유하지 못하는 상황에선 정의서를 작성하는 것이 최고의 커뮤니케이션 수단이었다고 생각합니다.

테스트 케이스 정의서

마찬가지로 처음엔 이 정의서를 만드는 일이 매우 귀찮았습니다.

하지만 작성이 완료되고 나서는 이 문서 하나로 다음과 같은 효과를 누릴 수 있었습니다.

  • API의 전체 흐름을 구조적으로 파악할 수 있었고
  • 담당자별 엔드포인트 관리가 가능했으며
  • 성공 여부 표시를 통해 구현 상태 파악이 쉬워졌습니다.

물론, Swagger가 이런 역할을 어느 정도 해주지만 Swagger는 실행 이후의 문서화이고 테스트 성공 여부나 담당자 등의 개발 과정에서 필요한 정보는 제공하지 못하기 때문에 개발 과정에서의 API 개발 흐름 관리측면에서 매우 효과적인 방법인 것 같습니다.

2. 하고 싶었던 것 및 아쉬운점

이번 프로젝트에서 제가 가장 중점을 둔 가치는 단순한 기능 구현이 아닌 기획과 설계 그리고 유지보수가 가능한 구조의 구축이었습니다.

인공지능이 일상적으로 활용되는 지금의 시대에 “기능을 구현할 줄 안다”는 것만으로는 큰 의미가 없다고 생각합니다.

진짜 중요한 것은 복잡한 요구사항을 설계로 구체화하고, 시스템을 유지보수 가능하게 설계하는 능력이라고 생각하기 때문에 이번 프로젝트에선 그러한 능력을 함양하는 것을 목표로 하였습니다.

기술적인 아쉬움

이번 프로젝트를 시작하며 제가 설정했던 핵심 목표는 다음과 같습니다.

  • CQRS 패턴을 도입하여 도메인 간 책임을 분리하는 구조 설계
  • 비동기 메시지 기반 아키텍처(RabbitMQ 등)의 적용
  • 모니터링 및 로깅을 통한 서버 안정성 확보
  • Redis 캐시 활용
  • 기술별 테스트 코드 작성

프론트엔드 프로젝트까지 모든 기술들을 접목할 수 있을진 모르겠지만 파이널 프로젝트에선 지금 프로젝트에서 사용했던 CQRS 패턴 구조 뿐만 아니라 파이널 프로젝트 주제에 적합한 패턴 구조를 채택하여 유지보수성을 높이고 MSA 구조에서 안정적으로 서버가 운영되고 자동배포되는 완벽한 서비스를 설계하고 구현하는 것이 저의 최종 목표가 될 것 같습니다.

리드하는 것에 대한 아쉬움

어쩌다보니 이번 프로젝트에서는 제가 팀을 이끄는 입장이 되었고, 동시에 많은 주요 기능을 직접 구현하게 되었습니다.

하지만 백엔드에 대해 본격적으로 공부한 지 얼마 되지 않은 상황에서 제가 맡은 기능을 구현하고 설계하는 과정에 동시에 리드하는 것은 결코 쉽지 않았습니다.

부족함을 느끼는 부분은 다음과 같습니다.

  • 제 역할에 집중하느라 다른 팀원들의 트러블슈팅에 충분히 도움을 주지 못했던 점
  • 전체 구조를 조율하면서 우선순위 설정과 태스크 전환에 어려움을 겪었던 점은 전문 개발자로서의 부족함을 체감하게 해주었습니다

분야는 다르지만이전 회사 경험을 떠올려보면 내 일만 잘하는 것은 결코 충분하지 않다는 것을 누구보다 잘 알고 있습니다.

팀원 간 요청이 동시다발적으로 들어올 때 빠르게 다른 업무로 전환을 할 수 있고 우선순위를 설정하여 전체 흐름을 관리할 수 있는 능력이 실무에서 무엇보다 중요한 진짜 실력이라고 생각했고 이전 회사에서 제 사수분을 보면서 가장 배우고 싶은 부분이 해당 능력이었습니다.

그런데도 아직 제가 담당한 일에 치여 다른 사람들의 일을 봐주지 못하는 저를 보며 더 큰 아쉬움을 느낄수밖에 없었습니다.

그래서 저는 프론트엔드 프로젝트에선 저희 이번 백엔드 프로젝트에서 가장 문제였던 버전 관리 도구인 깃과 깃허브와 관련하여 그럴듯하게 정리한 컨벤션이 아닌 팀내에서 실제로 적용할 수 있는 진짜 브랜치/커밋/코딩 컨벤션을 정착하는 것을 목표로 하고있습니다.

또한 저희 프로젝트에 대한 기반 지식이 없던 사람들도 바로 투입될 수 있는 문서화를 통해 협업 과정 자체를 시스템화하여 협업 과정 자체를 성장하는 연습을 해보고자 합니다.

3. 내가 한 것 및 할 것

이번 프로젝트에서 제가 맡은 주요 책임과 역할 그리고 그 과정에서 고민했던 설계, 기술적 시도와 의도를 중심으로 정리해보고자 합니다.

프로젝트 주요 담당 영역 정리

  • 프로젝트 노션 구조 설계
  • 전체 프로젝트 구조 설계 및 CQRS 패턴 기반 구조 설계
  • MSA 설계 및 구현
  • Spring Security 활용한 인증/인가 흐름 전반 구성
  • 공통 응답/예외 처리 구조화
  • 회원 도메인 및 포인트 도메인 전체 구현

프로젝트 노션 구조 설계

먼저 프로젝트의 협업 환경을 위한 노션 구조를 설계했습니다. 제 개인적으로 사용하고 있는 시간 관리 템플릿 기반으로 구성했고 여전히 이보다 더 직관적인 구조는 없는 것 같습니다.

저는 스크롤이 많은 인터페이스나 깊게 들어가야 하는 메뉴 구조는 사용자 경험 측면에서 불편하다고 생각합니다. 특히 프로젝트와 관련된 문서를 관리해야 하는 목적에서 사용하는 노션 페이지라면 한눈에 필요한 모든 자원에 접근할 수 있는 버튼들만 메인 페이지에 위치하면 된다고 생각합니다.

그래서 문서화 영역은 왼쪽, 작업(WBS)은 중앙, 산출물은 오른쪽에 배치하여 직관적인 동선과 즉시성 높은 접근성을 확보했고 향후 데브옵스나 파이널 프로젝트에서도 이 구조를 유지할 예정이지만, 더 나은 구조를 발견한다면 언제든지 개선할 생각입니다.

CQRS 패턴 구조 설계

📁 linkupUser
├── 📄 build.gradle
├── 📄 settings.gradle
├── 📁 src
│   └── 📁 main
│       ├── 📁 java
│       │   └── 📁 com.learningcrew.linkupuser
│       │       ├── 📄 LinkupUserApplication.java
│       │       ├── 📁 client
│       │       ├── 📁 command
│       │       │   └── 📁 application
│       │       │       ├── 📁 controller
│       │       │       ├── 📁 dto
│       │       │       └── 📁 service
│       │       ├── 📁 domain
│       │       │   ├── 📁 aggregate
│       │       │   └── 📁 repository
│       │       ├── 📁 infrastructure
│       │       │   └── 📁 repository
│       │       └── 📁 query
│       │           ├── 📁 controller
│       │           ├── 📁 dto
│       │           │   ├── 📁 request
│       │           │   └── 📁 response
│       │           ├── 📁 mapper
│       │           └── 📁 service
│       └── 📁 resources
│           ├── 📄 application.yml
│           └── 📁 mappers
│               └── 📄 사용자_Mapper.xml

백엔드 프로젝트를 시작하면서 가장 먼저 고민했던 것은 프로젝트 구조의 설계였습니다.

이전 프론트엔드 프로젝트 경험에서 컴포넌트가 무분별하게 퍼지고, 코드가 중복되며, 협업이 어려워지는 구조를 경험했기에 부트캠프에선 진행하는 프로젝트에선 꼭 맡은 기능과 책임을 기준으로 명확히 구분된 구조를 만들어야겠다는 생각을 했습니다.

그래서 그래서 클린코드 아키텍처 책을 읽으면서 클래스와 함수를 최대한 작게 나누고 유지보수성을 위해 구현체가 아니라 인터페이스에 의존하는 DIP를 구현하는 것까지는 알게되었는데 전체적인 프로젝트 구조를 어떻게 구성해야 할지는 전혀 감을 잡지 못한 상황이었습니다(프로젝트 구조 아키텍처가 아니라 “클린코드” 아키텍처이니 그럴수밖에….)

그런 와중에 강사님께서 소개해주신 CQRS(Command-Query Responsibility Segregation) 패턴은 말 그대로 “유레카”였습니다. Command(쓰기)와 Query(읽기)의 책임을 분리하면 코드가 명확해지고 각각 필요한 모듈과 구성만 갖추게 되어 파일 간 결합도가 낮고 유지보수성이 뛰어난 구조를 만들 수 있다는 것을 알게되었습니다.

Command Layer의 아키텍처 설계

특히 감명 깊었던 부분은 Command 영역 내의 Application Service와 Domain Service의 분리입니다.

Command측 구조에는 Application layer의 service가 있고 Domain측 Service가 있습니다.

저는 처음엔 둘다 Service가 있는지 가마득하게 잊고 그냥 단순한 MVC 구조처럼 Application layer의 Controller 핸들러에서 Application 내의 Service를 호출하고 바로 Domain 내의 Repository를 호출하여 DB에 반영되도록 했었는데 그렇다보니 너무 중복되는 코드가 많다는 것을 느꼈습니다.

그래서 중복되는 코드들을 어디에서 관리할까 util 폴더를 만들까 했는데 생각해보니 Domain내에도 Service가 있다는 것을 뒤늦게 깨달았고 지금은 Application Service측에선 비즈니스 로직을 처리하기 위해 Domain Service를 조율하는 역할만 하고 실제 코드 구현은 Domain Service 측에서 담당하고 있고 여러 Domain 내에서의 공통된 코드가 있을 때만 common측 service에서만 넣어서 관리하고 있습니다.

그 결과 기능별 관심사가 명확히 분리된 구조를 갖추게 되었고, 유지보수성과 테스트 편의성이 크게 향상되었습니다.

결합도 해소와 리팩토링

클린코드 아키텍처에서는 클래스간의 결합도 척도를 스태틱 변수와 인스턴스 변수가 클래스 내부에서 모든 메서드들이 사용하고 있는지 얼만큼 사용하고 있는지에 따라 측정합니다.

처음엔 Application Service에서 Repository를 그대로 의존성 주입해서 사용했기 때문에 사용하는 테이블의 개수만큼 Repository를 의존성 주입받아서 사용하게 되었고 결국엔 클래스 내부의 메서드들중 일부만 사용하는 Repository가 늘어나게 되었고 이것은 유지보수성과 확장성 관점에서 추후 문제가 될 것이라는 것을 깨닫고 위에서 말했듯이 재사용할 수 있는 코드들은 Domain Service 내의 메서드를 추가하여 해당 코드를 재사용하도록 리팩토링 하였고 컨트롤러와 서비스를 이메일 관련 된것이나 친구 관련 된 것이나계정과 관련된 것이나 인증과 관련된 것을 다 다른 컨트롤러 클래스와 서비스 클래스로 구분하게 되었습니다.

물론 아직 User 도메인에 인증 관련된 기능들이 포함되어 있어서 아직 완벽하게 쪼갠 것은 아니긴 합니다. 그래서 추후에 확장성을 생각하면 인증과 관련된 것도 별도의 도메인으로 나눠서 관리하고자 합니다.

DIP 원칙 적용

처음에 구현할 땐 컨트롤러에서 서비스를 호출할 때 바로 서비스 구현체의 메서드를 호출했는데요. 다른 팀의 동기 동생의 코드를 보면서 동기 동생이 서비스 구현체가 아닌 인터페이스를 의존하여 의존성 주입을 하는 것을 확인할 수 있었고 생각해보니 제가 작성한 코드는 클래스와 서비스간의 강한 의존성이 생기는 것을 확인할 수 있었고 클린코드 아키텍처에서 학습한 DIP와 관련된 내용이 생각났습니다. 그래서 컨트롤러에서 서비스 구현체를 의존하는 것이 아니라 인터페이스를 의존하도록 수정하였고 서비스 구현체는 숨겨서 언제든 구현체를 변경할 수 있는 구조로 리팩토링 하였습니다.

아직 전체적인 프로젝트 구조상에선 DIP가 지켜지지 않고 있는것 같아서 이부분은 문서화를 하여 팀원분들과 공유하여 전체적으로 구조상 DIP를 잘 지킨 프로젝트를 만들면 좋을 것 같습니다.

공통 응답 및 예외처리 구조 정형화

이번 프로젝트에서 제가 팀원들에게 실질적인 도움을 줄 수 있었던 부분은 공통 응답 구조와 예외 처리 구조의 정형화이지 않을까 싶습니다.

지금 상황에선 저희가 백엔드와 프론트 모두 담당하고 있긴 하지만 제가 프론트엔드만 담당했을 땐 서버로부터 전달받는 요청의 타입이 매번 다른 것은 정말 최악이었습니다. 왜냐하면 응답받는 데이터 타입이 동일하면 유틸 메서드 하나로 의도한 데이터에 접근하면 되는데 매번 다른 응답이 오게 되면 api별로 다른 파싱 코드를 작성해야 하므로 매우 불편했습니다.

그래서 이제 응답을 날리는 입장이 되는 사람이 되었으니깐 꼭 구조화하여 날려야겠다는 생각을 하게 되고 모든 응답을 ApiResponse로 묶어서 data 필드에 무조건 data가 들어가서 프론트에서 받을 수 있도록 구조화하였습니다.

그리고 예외가 발생했을 때 모든 예외들을 처리할 수 있는 GlobalExceptionHandler를 구현하였고 팀원들별로 커스텀한 Exception 클래스 뿐만 아니라 인증 및 인가 실패에 대한 예외 처리, 유효성 검사 예외 처리, 예상하지 못한 모든 예외들까지도 모두 받을 수 있도록 하였고 각각의 예외 클래스에서 메세지와 상태코드를 추출하여 공통 ErrorResponse를 생성하여 응답을 보낼 수 있도록 모두 구조를 잡아놓았습니다.

그래서 다른 팀원분들은 미리 만들어 놓은 예외 클래스로 ErrorCode와 메세지를 넣어서 날리기만 하면 미리 세팅해둔 설정에 따라 에러 메시지와 상태 코드가 포함되서 응답으로 전달되니 프론트엔드에선 항상 일정한 예외 구조의 응답을 받게 될 뿐만 아니라 예외를 처리하는 것을 단순화할 수 있었습니다.

해당 구조는 매우매우 마음에 드는 구조이고 처음 구조한 이외로 변경되는 부분이 없이 잘 사용하고 있고 문제는 ErrorCode Enum에 모든 ErrorCode를 넣다보니 팀원들별로 추가나 수정이 빈번하게 발생하게 되었고 병합하기 이전에 존재하던 ErrorCode가 병합 이후에는 없어지는 경우가 빈번하게 발생하게 되었습니다.

그래서 여기서 얻은 깨달음은 절대 모든 팀원들이 빈번하게 수정하는 코드엔 모두 집어넣으면 안되겠닫는 것을 절실히 깨닫게 되었습니다. 그래서 ErrorCode Enum도 도메인별로 나눠야 할지 지금 고민중이고 ErrorCode뿐만 아니라 서로 공통으로 사용하고 있는 클래스들중에서 빈번하게 수정이 필요한 것은 뭐가 있고 무엇을 나눠야 할지 고민하고 있는 상황입니다.

실무에선 더 많은 사람들끼리 같은 파일을 수정하게 될텐데 그때를 생각해보면 어떻게 안정적으로 많은 사람들간에 공통적으로 사용하는 파일을 관리할 수 있을지에 대해 고민해볼 수 있는 정말 좋은 기회였고 가장 좋은 것은 공통으로 접근할 코드의 경우엔 미리 컨벤션을 맞추는 것이 필요하고 최대한 파일을 작게 나눠서 관리하는 것이 좋고 언제든지 확장할 수 있는 구조를 갖추는 것이 중요할 것 같습니다.

MSA 설계 및 구현

이번 프로젝트에서 가장 구조적으로 큰 변화는 모놀로식에서 MSA(Microservice Architecture) 구조로 전환한 경험이었습니다.

처음에는 하나의 서버로 모든 기능을 처리하는 모놀로식 구조에서 시작했지만, 점차 도메인의 독립성과 확장 가능성을 고려하여 회원(User) 도메인을 별도의 서비스로 분리하였고, 이를 기점으로 전체 구조를 MSA로 전환하였습니다.

MSA 구조는 다음과 같은 구성을 기반으로 설계했습니다.

  • Spring Cloud Gateway: 단일 진입점. 인증 필터를 처리하며 라우팅 책임을 수행.
  • Eureka Server: 마이크로서비스들의 서비스 등록/탐색을 위한 레지스트리.
  • Feign Client: 마이크로서비스 간의 통신을 추상화하여 각 서비스 간 직접 호출 가능.
  • User-Service, Common-Service 등: 각각의 도메인에 대한 독립 서비스 구성.

저희는 처음엔 모놀로식으로 모든 기능을 구현한 후에 나중에 제가 구현하고 있던 도메인인 User를 기존 서버에서 분리시켜 새로운 User 서버를 구현하였고 추가적으로 Eureka Server와 Spring Cloud Gateway를 구현하여 Eureka Server에서 Spring Cloud Gateway, User Service, Common Service를 관리하고 단일 진입점인 Gateway에서 인증에 대한 책임을 전가하고 각각의 마이크로 서비스에선 인가에 대한 검사를 하고 인스턴스간 통신은 Gateway를 거치는 방식이 아니라 인스턴스간 직접적인 통신을 할 수 있도록 MSA 구조를 설계하였습니다.

서비스 간의 통신은 Gateway를 반드시 거치지 않고, 필요에 따라 Feign을 통한 직접 호출 방식도 병행하였습니다. 이는 인증의 흐름은 Gateway가 책임지고, 인가는 각 서비스 내부에서 처리하는 구조로 역할을 분리하기 위함입니다.

하나의 서버내에 모든 관련된 기능들이 포함된 구조가 아니라 통신을 통한 기능 구현 구조로 변경되었기 때문에 User 서버가 켜져있어도 Common 서버가 다운되면 문제가 될 수 있기 때문에 운영 안정성을 높일 수 있는 대책도 필요하고 에러가 발생했을 때 다른 마이크로서비스에 에러가 전파되지 않도록 하고 설정 정보를 한 곳에서 관리하는 추가적인 작업이 필요하다는 것을 알고 있기에 아직 완벽한 MSA를 구현하지 못한 것이 아쉬울 뿐입니다.

따라서 추후 Config Server, 로그 집계, 트래픽 모니터링, 장애 감지 등의 운영 안정화 도구들은 이후 도입할 예정이고 가능하다면 실시간 장애 알림(Discord Webhook 등)까지 구현하여 운영 대응 체계도 세우고 싶습니다.

Spring Security 및 보안 구조 설계

저는 프론트엔드를 했을 땐 보안에 대한 생각을 깊게 해본적이 없습니다. 오히려 보안을 강화하는 것에 대해 사용자 경험 측면에서 안좋게 바라봤습니다. 그래서 로그인을 하지 않는 앱이 사용자가 회원가입이나 로그인을 해야 하는 번거로움을 한번 들여주니깐 좋은 앱이지 않을까 하는 생각을 했었는데 백엔드를 공부하면 할수록 사용자 경험을 좋게 하는 것은 단순히 디자인이 예쁘거나 번거로움을 줄여주거나 의도한대로 액션이 일어나는 것 뿐만 아니라 이 서비스를 믿고 사용할 수 있도록 하는 것이 아닐까라는 생각을 점점 하게 되었습니다.

그래서 서버 안정성을 위해 위에서 MSA 구조도 서버 부하와 에러 위임 전파 방지 관점에서 중요한 설계란 생각이 들었고 보안 역시 사용자가 믿고 사용하기에 매우 중요한 부분이 아닐까라는 생각을 하게되었습니다.

처음엔 Spring Security를 사용하면 그냥 보안이 강력하게 될 줄 알았습니다. 왜냐하면 그냥 이해하는 것조차 어려웠거든요….ㅎ 그런데 점점 공부하다보니 Spring Security가 해주는 것은 인증과 인가를 조금 더 간편하게 처리할 수 있도록 해주는 도구라는 것을 깨달았습니다.

요청에서 컨트롤러까지 오는 그 과정에서 필터를 설정하여 인증과 인가에 대한 필터를 설정할 수 있고 인증 필터에선 기본적으론 아이디와 비밀번호로 인증을 처리하거나 아니면 JwtTokenAuthentication과 같은 커스텀 필터를 만들 수 있도록 해주는 것이지 결국엔 제가 필터 인터페이스를 구현해서 필터 구현체를 생성하고 해당 필터 구현체 내부에서 발급해준 토큰의 유효성을 검사하고 유효하면 다음 필터로 넘어가는 것을 직접 설정해주어야 했고 보안을 높이는 기능은 Spring Security에게 없다는 것을 알았습니다.

그래서 JwtToken을 사용할 때 다들 사용하는 공통 방법인 AccessToken과 refereshToken 두개를 만들어서 AccessToken의 유효시간을 짧게 하고 AccessToken의 유효시간이 다되었을 때 refereshToken을 클라이언트로부터 전달받아서 DB에 있으면 다시 AccessToken을 발급해주는데 이렇게만 구현하면 로그아웃하고 10분동안 특정 회원의 AccessToken을 막을 방법이 없게 되서 블랙리스트 테이블에 로그아웃을 하게 되면 해당 회원을 넣고 인증시에 블랙리스트 테이블에서 해당 회원이 있는지를 확인하는 작업을 처리하였습니다. 그런데 해당 작업은 DB로 처리하기엔 매번 api 호출마다 DB에서 조회해야 하는 다소 리소스가 필요한 작업이기 때문에 추후에 Redis를 사용하여 적은 리소스로 높은 성능으로 빠르게 처리할 수 있도록 리팩토링 할 계획입니다.

그리고 계좌 정보를 저장하고 환불을 처리하는 과정에서 보안 취약점에 대해 고민해보게 되었는데요, 현재는 DB에 계좌 정보를 직접 저장하고 있지만 이는 지불 카드 산업 데이터 보안 표준 기준에서 문제가 될 수 있다는 것을 백엔드 프로젝트 이후에 다른 동료분들을 통해 알게되었습니다.

그래서 저는 향후에는 PG사에 계좌 정보를 저장하고 사용자-계좌 연동에 필요한 토큰 정보만을 보관하는 방식으로 전환할 예정입니다.

3. 배운점 및 느낀점

문서화

이번 프로젝트는 저에게 기술적인 성장 그 자체였고 동시에 소통과 협업의 본질에 대해 깊이 고민하게 해준 소중한 경험이었습니다.

프로젝트를 진행하면서 제가 맡은 도메인이나 기능들이 다소 복잡하고 규모가 크다 보니, 팀원 분들께서 고맙다는 말을 자주 전해주셨습니다. 그런데 실제로는 저야말로 이런 수준 높은 요구사항과 다양한 기술 스택을 실험해볼 수 있는 기회를 주신 팀원 분들께 더 감사한 마음이었습니다.

그러나 프로젝트를 진행하면서 한가지 아쉬움이 남았습니다.

한편, 제가 경험하고 체득한 지식과 기술을 충분히 공유하지 못했다는 점에서는 상당한 아쉬움도 남았습니다. 그로 인해 “내가 알고 있는 것”과 “팀이 함께 알고 있는 것”의 간극이 생길 수 있다는 사실을 체감했고, “모든 것은 결국 문서화로 완성된다”는 교훈을 얻게 되었습니다.

제가 이번 프로젝트에서 문서화로 남긴 부분은 다음과 같습니다.

  1. 프로젝트 구조 및 디렉토리 컨벤션

  2. 예외 처리 구조 및 사용 방법

  3. 환경 변수 등록 가이드

  4. MSA 구조 전환 가이드

  5. 코딩 컨벤션 및 코드 스타일

  6. 한/영 표기 기준

  7. 브랜치 컨벤션 및 관리 기준

위의 문서들을 작성하며 가장 고민했던 것은 다음과 같습니다.

  • 이 문서가 과연 다른 사람에게 진짜 ‘전달’이 되고 있는가?

저의 개인적인 관점에선 충분한 설명이라 여겼지만 팀원들이 이해하지 못하는 경우를 많이 보게 되었고 그 과정을 통해 문서의 품질은 누구에게 잘보이기 위한 것이 아니라 팀원의 이해도에 달려 있다라는 것을 깨달았습니다.

그래서 앞으로는 더 많은 예시와 시각적 정리 그리고 직관적인 표현 방식을 통해 구조적으로 예쁜 문서가 아닌 팀원들이 이해하기에 용이한 완벽한 문서를 작성하는 것이 저의 목표입니다.

소통을 위한 안건함

저번 DB 프로젝트를 진행하면서 소통의 문제점을 언급한바 있고 소통 문제를 해결하기 위한 방법으로써 안건함을 다음 프로젝트에서 진행해보고 싶다고 얘기한바 있고 이번 프로젝트에서 안건함을 도입해서 진행해봤습니다.

처음에는 ERD 작성까지는 활용도가 낮았지만, 서버 개발이 시작되면서부터는 팀 내 의사결정과 논의 사항을 정리하는 데 큰 도움이 되었습니다. 하지만 여전히 다음과 같은 한계가 있었습니다.

  • 제목만 있고 내용이 비어있는 경우가 많다
  • 작성된 안건을 확인하지 않는 경우도 존재

이러한 문제를 보완하기 위해선 다음과 같은 체계적인 관리가 필요하다는 생각을 하게 되었습니다.

  • 안건 작성 양식의 표준화
  • 확인 여부를 표시할 수 있는 체계 구축
  • 디스코드 혹은 슬랙과 연동하여 알림 시스템 구현

회고록은 정말 중요하다

저번 DB 프로젝트 진행에 있어 정말 중요했던 것이 바로 회고록이였습니다. 그래서 이번 프로젝트에도 회고록을 도입했고 정말 감사하게도 같은 팀원분중 여진님께서 저희가 진행했던 팀미팅에 대한 회고록을 많이 담당해주셨습니다.

작성된 회고록을 통해 일정시간이 지난 후에도 저희가 무슨 얘기를 했었고 어떤 생각이었는지를 쉽게 확인할 수 있었고 각 회의별 액션 아이템을 추출하여 본질적으로 무엇을 해야할지에 대해 한눈에 확인하고 정리하는데 매우 도움이 되었던 것 같습니다.

ChatGPT는 나의 자동화 도구

저는 이번에 ChatGPT를 최대한 사용하지 않을 생각이었고 처음 코드 구현과정에선 모든 코드를 제가 작성했고 공부할 때만 개념의 깊이를 높이고 개념이 맞는지 확인하는 목적으로만 사용했던 것 같습니다.

왜냐하면 이전 자바 미니 프로젝트를 진행 했을 때 ChatGPT에 의존해서 프로젝트를 진행했었는데 결국에 남는 것은 아무것도 없다는 것을 허무함을 크게 느꼈기 때문입니다.

그런데 코드를 작성하다보니 동일하진 않지만 형식이 비슷한 코드들을 계속해서 작성하게 되고 제가 A부터 Z까지 작성할 수 있는 코드를 매번 처음부터 구현하는 것은 비효율적이라는 생각이 들었습니다.

그래서 제가 구조화한 틀 안에서 내가 원하는 스타일로 빠르게 코드를 생성하는 도구로서 ChatGPT를 사용했고 내가 구현할 수 없는 코드를 무비판적으로 받아들이는 것을 엄격하게 차단하고 자동화 파트너로서만 사용하는 것은 지금 시대에 효율적으로 업무를 처리하는 기술이지 않을까 싶습니다.

profile
지속 가능한 개발과 꾸준한 성장을 목표로 하는 Web Developer 박성용입니다

1개의 댓글

comment-user-thumbnail
2025년 4월 21일

와.. 거의 책쓰셨는데요!! 멋져요!

답글 달기