예약 기능을 완성하고 테스트까지 성공했는데 데이터베이스 구조가 너무 비효율적이라 생각해서 수정을 하기로 결심했다.
기존 DOCTOR_SCHEDULE 테이블에는 의사 1명당 5개의 근무 데이터가 필요했다. 하지만 모든 의사의 진료 시간은 평일 9-6, 주말 9-2로 고정되기 때문에 굳이 시간을 DB에 저장할 필요가 없었다.
그래서 DOCTOR_SCHEDULE 테이블을 제거하고 병원 운영 시간은 application.yml 설정 파일로 관리하고 의사 휴무일은 DOCTOR 테이블에 day_off 컬럼을 추가하는 방식으로 변경했다.
이렇게 하면 의사 1명당 데이터가 1개로 줄어들고 휴무일이 변경 시 dayOff 컬럼만 업데이트하면 돼서 유지보수성도 좋아진다. 결과적으로 중복 데이터는 사라지고 운영 시간 관리는 더 유연해졌다.
[리팩토링 과정]
1. DOCTOR_SCHEDULE 테이블 제거
2. Doctor 엔티티 수정 - day_off 컬럼 추가
@Entity
@Getter @Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Doctor extends BaseEntity{ // BaseEntity 상속(created_at 필드 자동 상속)
...
// 개인 휴무일
@Column(name = "day_off", length = 10)
private String dayOff;
// dayOff 추가
public static Doctor createDoctor(String name, Department department, String dayOff) {
Doctor doctor = new Doctor();
doctor.setName(name);
doctor.setDepartment(department);
doctor.setDayOff(dayOff);
return doctor;
}
}
이제 의사는 근무 시간이 아닌 쉬는 날 정보만 가진다.
3. resources/application.yml 설정 - 병원 운영 시간 추가
hospital:
schedule:
weekday:
start-time: "09:00"
end-time: "18:00"
saturday:
start-time: "09:00"
end-time: "14:00"
lunch:
start-time: "13:00"
end-time: "14:00"
운영 시간은 설정 파일로 분리하여 관리한다.
4. HospitalProperties 클래스 - 설정값을 Java 객체로 변환
@Getter @Setter
@Component
@ConfigurationProperties(prefix = "hospital.schedule")
public class HospitalProperties {
private TimeSlot weekday;
private TimeSlot saturday;
private TimeSlot lunch;
// 내부 클래스: 시작,종료 시간-
@Getter @Setter
public static class TimeSlot {
private String startTime; // yml의 start-time과 자동 매핑
private String endTime;
}
}
@ConfigurationProperties(prefix = "hospital.schedule"): yml의 hospital.schedule 하위 값들을 자동으로 매핑
5. DoctorScheduleRepository 삭제 - DoctorService 생성
DOCTOR_SCHEDULE 테이블이 사라졌으므로 이를 조회하던 Repository도 삭제했다.
기존에는 DoctorScheduleRepository를 조회해서 모든 정보를 DB에서 가져왔는데 이제는 2단계 검증 로직으로 변경했다.
1단계: 병원 운영 시간 확인 (.yml)
2단계: 의사 휴무일 확인 (DB)
이렇게 설정과 데이터를 분리하여 효율성을 높였다.
6. Controller 구현 - 변경된 로직 연결
서비스 계층에서 '계산된 예약 가능 시간'을 반환 로직(getAvailableSlots)을 완성했고 이를 프론트엔드에서 호출할 수 있도록 API를 연결했다. 기존에는 DB를 바로 조회했는데 이제는 Service를 통해 계산된 결과를 반환한다.
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1")
public class DepartmentController {
private final DoctorService doctorService;
...
@GetMapping("/doctors/{doctorId}/availability")
public List<LocalTime> getDoctorAvailability(
@PathVariable("doctorId") Long doctorId,
@RequestParam("date") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date) {
// DoctorService의 getAvailableSlots 메서드 호출 (예약 가능 시간 계산)
return doctorService.getAvailableSlots(doctorId, date);
}
}
7. Frontend(TypeScript) 동기화
interface Doctor {
id: number;
name: string;
dayOff: string; // 백엔드 엔티티 변경 사항 반영
department: {
id: number;
deptName: string;
};
}
마지막으로 백엔드의 바뀐 데이터 구조대로 프론트엔드의 타입 정의도 맞춰야 한다. DOCTOR 엔티티에 day_off 필드가 생겼으므로 TypeScript Interface에도 이를 추가했다. 이렇게 타입을 맞춰두면 백엔드 변경 사항을 놓치지 않고 안전하게 개발할 수 있다.
이번 리팩토링을 통해 데이터 중복을 없애고 운영 시간을 유연하게 관리하며, API 계층까지 깔끔하게 연결했다. 처음엔 '그냥 테이블 하나 지우는 건데?' 라고 가볍게 생각했지만 그 과정에서 객체지향적인 책임 분리와 유지보수성에 대해 깊게 고민해볼 수 있었다.
'DevLog' 카테고리의 다른 글
| 병원 예약 시스템 Part 2 - 예약 비즈니스 로직 구현과 프론트엔드 연동 (0) | 2025.12.09 |
|---|---|
| 병원 예약 시스템 Part 1 - 프로젝트 세팅과 기술 선정 이유 (MyBatis vs JPA) (0) | 2025.12.08 |