본문 바로가기
-- 오늘 있었던 개발 일기

테이블 설계...

by code study 2026. 1. 28.

Creator-Flex 프로젝트에서 휴가 관리 기능을 개발하던 중 문제를 발견했다.

처음에는 간단하게 생각했다. "휴가 신청 내역에서 시작일~종료일 계산해서 총 연차 15일에서 빼면 되지 않을까?"

// 초기 구상
public int getRemainingVacation(Long memberId) {
    List<Vacation> vacations = findApprovedVacations(memberId);
    int usedDays = vacations.stream()
        .mapToInt(v -> calculateDays(v.getStartDate(), v.getEndDate()))
        .sum();
    return 15 - usedDays;
}

 

 

그런데 Figma로 UI를 구성하다가 문제가 생겨났다.

남은 연차를 보여줘야 하는 곳이 생각보다 너무 많았다.

  • 메인 대시보드
  • 휴가 신청 페이지
  • 마이페이지
  • 관리자 전체 직원 목록
  • HR 대시보드
  • 통계 페이지

"이걸 매번 계산하면... 성능 괜찮을까?"

성능에대해 고민해보니

개인 대시보드: 약 200ms (괜찮음)

관리자 - 전체 직원 100명 조회:
100명 × 200ms = 20초

이건 안 된다!

고민의 시작

팀원들과 회의를 했다.

문혁진: "직원 테이블에 남은연차 컬럼 추가하면 안 돼요?"
이상명: "휴가 테이블에 사용일수 컬럼 넣는 건요?"

일리 있는 제안이었지만 뭔가 찝찝했다.

문제점:
- 연도별 관리는? (2024년 vs 2025년)
- 데이터 불일치 위험
- 연차 이월은 어떻게?
- 이력 추적은?

해결책: VacationBalance 테이블 생성

고민 끝에 별도 테이블을 만들기로 했다.

CREATE TABLE vacation_balance (
    balance_id LONG PRIMARY KEY,
    member_id LONG,
    year INT,                    -- 연도별 관리
    total_vacation DECIMAL,      -- 15
    used_vacation DECIMAL,       -- 3
    remaining_vacation DECIMAL,  -- 12
    updated_at DATETIME
);

선택 이유

  1. 성능 해결 - 조회 시 계산 없이 바로 가져옴
  2. 연도별 관리 - 2024년, 2025년 연차 따로 관리
  3. 이력 추적 - 과거 데이터 보관 가능
  4. 확장성 - 통계, 이월 처리 쉬움

구현

Entity

@Entity
public class VacationBalance {
    @Id
    private Long balanceId;

    @ManyToOne
    private Member member;

    private Integer year;
    private BigDecimal totalVacation;
    private BigDecimal usedVacation;
    private BigDecimal remainingVacation;

    // 휴가 사용
    public void useVacation(BigDecimal days) {
        this.usedVacation = this.usedVacation.add(days);
        this.remainingVacation = this.totalVacation.subtract(this.usedVacation);
    }

    // 휴가 취소
    public void cancelVacation(BigDecimal days) {
        this.usedVacation = this.usedVacation.subtract(days);
        this.remainingVacation = this.totalVacation.subtract(this.usedVacation);
    }
}

Service 로직

@Service
@Transactional
public class VacationService {

    // 휴가 승인
    public void approveVacation(Long vacationId) {
        Vacation vacation = findVacation(vacationId);
        VacationBalance balance = findBalance(vacation.getMemberId());

        // 잔여연차 체크
        if (balance.getRemainingVacation()
            .compareTo(vacation.getVacationDays()) < 0) {
            throw new InsufficientVacationException();
        }

        // 승인 처리
        vacation.approve();
        balance.useVacation(vacation.getVacationDays());
    }

    // 조회 (빠름!)
    public VacationBalanceDto getMyBalance(Long memberId) {
        VacationBalance balance = balanceRepository
            .findByMemberIdAndYear(memberId, 2025)
            .orElseThrow();

        return VacationBalanceDto.from(balance);
    }
}

결과

Before (계산 방식)

전체 직원 100명 조회: 20초

After (VacationBalance 테이블)

전체 직원 100명 조회: 50ms
400배 빨라짐!

배운 점

"성능 문제는 설계 단계에서 고민해야 한다"

처음에는 간단하게 계산으로 처리하려 했지만, UI 요구사항을 보고 휴가관련 로직들을 개발하다보니 해당 문제를 발견했다.

만약 개발 다 끝나고 나서 "너무 느려요!" 라는 피드백을 받았다면, 전체를 다시 뜯어고쳐야 했을 것이다.

앞으로는 설계단계에서 확실이 개발 후에 유지보수 관점에서 또한 최선을 다할수 있는 코드로 계획해야 한다는 것을 이번 경험을 통해 다시금 느끼게되었다.

'-- 오늘 있었던 개발 일기' 카테고리의 다른 글

트랜잭션의 격리 수준  (0) 2026.02.01
더미 데이터에 시퀀스?  (1) 2026.01.29
spring MVC에 대해서  (0) 2026.01.16
aws에 대해하여!  (0) 2026.01.06
2026년도 새해가 왔다  (0) 2026.01.05