AI 프롬프트 사용 예시
기술 질문 예시
예시 1: 성능 최적화 질문
User: Spring Boot 애플리케이션의 응답 시간을 개선하고 싶어. 현재 평균 500ms인데 200ms 이하로 줄이려면 어떻게 해야 할까?
AI Assistant:
문제 이해
Spring Boot 애플리케이션의 응답 시간을 500ms에서 200ms 이하로 개선하려는 요구사항입니다.
해결 방안
방안 1: 데이터베이스 쿼리 최적화
- 장점: 가장 큰 성능 향상 기대
- 단점: 쿼리 분석 시간 필요
- 예제 코드:
// N+1 문제 해결 - Fetch Join 사용
@Query("SELECT u FROM User u LEFT JOIN FETCH u.orders WHERE u.id = :userId")
fun findUserWithOrders(@Param("userId") userId: Long): User?
// 인덱스 추가
@Table(indexes = [
Index(name = "idx_user_email", columnList = "email"),
Index(name = "idx_created_at", columnList = "createdAt")
])방안 2: 캐싱 전략 구현
- 장점: 즉각적인 성능 향상
- 단점: 캐시 일관성 관리 필요
- 예제 코드:
@Configuration
@EnableCaching
class CacheConfig {
@Bean
fun cacheManager(): CacheManager {
return ConcurrentMapCacheManager("users", "products")
}
}
@Cacheable(value = ["users"], key = "#userId")
suspend fun findUser(userId: Long): User {
return userRepository.findById(userId)
}추천 솔루션
데이터베이스 쿼리 최적화와 캐싱을 함께 적용하는 것을 추천합니다.
구현 단계
- 느린 쿼리 식별 (Spring Boot Actuator 활용)
- 쿼리 실행 계획 분석
- 인덱스 추가 및 쿼리 최적화
- Redis 캐시 도입
- 성능 측정 및 모니터링
참고 자료
예시 2: 아키텍처 설계 질문
User: 우리 서비스를 모놀리식에서 MSA로 전환하려고 하는데, 어떤 순서로 진행하면 좋을까?
AI Assistant:
문제 이해
모놀리식 아키텍처를 마이크로서비스 아키텍처(MSA)로 단계적으로 전환하는 전략이 필요합니다.
전환 전략
1단계: 도메인 경계 식별
// 도메인 모듈 분리 예시
modules/
├── user-domain/
├── order-domain/
├── payment-domain/
└── notification-domain/2단계: Strangler Fig 패턴 적용
- 기존 모놀리스를 유지하면서 점진적 분리
- API Gateway를 통한 라우팅
// API Gateway 설정
@Configuration
class GatewayConfig {
@Bean
fun routeLocator(builder: RouteLocatorBuilder): RouteLocator {
return builder.routes()
.route("user-service") { r ->
r.path("/api/users/**")
.uri("http://user-service:8081")
}
.route("legacy-monolith") { r ->
r.path("/**")
.uri("http://monolith:8080")
}
.build()
}
}3단계: 데이터베이스 분리
- 공유 데이터베이스에서 서비스별 DB로 전환
- 이벤트 소싱 패턴 도입
- Saga 패턴으로 분산 트랜잭션 처리
4단계: 서비스 간 통신
// gRPC 통신 예시
@GrpcService
class UserGrpcService : UserServiceGrpcKt.UserServiceCoroutineImplBase() {
override suspend fun getUser(request: GetUserRequest): UserResponse {
return userService.findById(request.userId)
.toGrpcResponse()
}
}주의사항
- 분산 트랜잭션 처리 전략 수립
- 서비스 간 통신 실패 대응
- 모니터링 및 추적 시스템 구축
- 조직 구조 변경 고려
참고 자료
코드 리뷰 예시
예시 3: 코드 개선 요청
User: 이 코드 좀 리뷰해줘:
class UserService {
fun getUsers(): List<User> {
val users = mutableListOf<User>()
val result = jdbcTemplate.query("SELECT * FROM users")
for (row in result) {
val user = User()
user.id = row.getLong("id")
user.name = row.getString("name")
user.email = row.getString("email")
users.add(user)
}
return users
}
}AI Assistant:
코드 분석
전반적으로 개선이 필요한 레거시 스타일의 코드입니다. Kotlin과 Spring의 모던한 기능을 활용하지 못하고 있습니다.
개선 사항
1. 의존성 주입 및 Repository 패턴 적용
현재 코드: 직접 jdbcTemplate 사용 개선된 코드:
@Repository
class UserRepository(
private val jdbcTemplate: JdbcTemplate
) {
fun findAll(): List<User> = jdbcTemplate.query(
"SELECT id, name, email FROM users",
UserRowMapper()
)
}
@Service
class UserService(
private val userRepository: UserRepository
) {
fun getUsers(): List<User> = userRepository.findAll()
}2. 데이터 클래스 및 RowMapper 활용
현재 코드: Mutable 객체와 수동 매핑 개선된 코드:
data class User(
val id: Long,
val name: String,
val email: String
)
class UserRowMapper : RowMapper<User> {
override fun mapRow(rs: ResultSet, rowNum: Int) = User(
id = rs.getLong("id"),
name = rs.getString("name"),
email = rs.getString("email")
)
}3. Spring Data JPA로 마이그레이션 고려
@Entity
@Table(name = "users")
data class User(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0,
val name: String,
val email: String
)
@Repository
interface UserRepository : JpaRepository<User, Long>모범 사례 적용
- 의존성 주입 패턴
- 불변 데이터 클래스
- Repository 패턴
- 함수형 프로그래밍 스타일
- 페이징 처리 추가
- 예외 처리 개선
추가 권장사항
- 대용량 데이터 처리 시 페이징 구현
- 캐싱 전략 도입 검토
- 비동기 처리 고려 (Coroutines)
문제 해결 예시
예시 4: 에러 해결 요청
User: Spring Boot 애플리케이션 시작할 때 이런 에러가 나와:
BeanCreationException: Error creating bean with name 'dataSource':
Failed to determine a suitable driver class
AI Assistant:
문제 이해
데이터베이스 드라이버 클래스를 찾지 못해 DataSource 빈 생성에 실패하는 문제입니다.
해결 방법
1. 의존성 확인
build.gradle.kts:
dependencies {
// 사용하는 DB에 맞는 드라이버 추가
implementation("org.postgresql:postgresql") // PostgreSQL
// implementation("mysql:mysql-connector-java") // MySQL
// implementation("com.h2database:h2") // H2
}2. application.yml 설정
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mydb
username: user
password: password
driver-class-name: org.postgresql.Driver # 명시적 지정3. 프로파일별 설정
# application-local.yml
spring:
datasource:
url: jdbc:h2:mem:testdb
driver-class-name: org.h2.Driver
# application-prod.yml
spring:
datasource:
url: ${DB_URL}
username: ${DB_USERNAME}
password: ${DB_PASSWORD}디버깅 체크리스트
- 의존성 추가 확인
- application.yml 설정 확인
- 환경 변수 설정 확인
- 프로파일 활성화 확인:
-Dspring.profiles.active=local
일반적인 원인
- DB 드라이버 의존성 누락
- 잘못된 JDBC URL 형식
- 프로파일 설정 오류
- 환경 변수 미설정
새로운 기능 구현 예시
예시 5: 기능 구현 요청
User: JWT 기반 인증 시스템을 구현하고 싶어. Spring Security와 함께 어떻게 설정하면 될까?
AI Assistant:
구현 계획
JWT 기반 인증 시스템을 Spring Security와 통합하여 구현합니다.
구현 단계
1. 의존성 추가
dependencies {
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("io.jsonwebtoken:jjwt-api:0.11.5")
runtimeOnly("io.jsonwebtoken:jjwt-impl:0.11.5")
runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.11.5")
}2. JWT 유틸리티 클래스
@Component
class JwtTokenProvider(
@Value("\${jwt.secret}") private val secret: String,
@Value("\${jwt.expiration}") private val expirationInMs: Long
) {
private val key = Keys.hmacShaKeyFor(secret.toByteArray())
fun generateToken(authentication: Authentication): String {
val now = Date()
val expiryDate = Date(now.time + expirationInMs)
return Jwts.builder()
.setSubject(authentication.name)
.setIssuedAt(now)
.setExpiration(expiryDate)
.signWith(key)
.compact()
}
fun validateToken(token: String): Boolean {
return try {
Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token)
true
} catch (ex: Exception) {
false
}
}
}3. Security 설정
@Configuration
@EnableWebSecurity
class SecurityConfig(
private val jwtAuthenticationEntryPoint: JwtAuthenticationEntryPoint,
private val jwtAuthenticationFilter: JwtAuthenticationFilter
) {
@Bean
fun filterChain(http: HttpSecurity): SecurityFilterChain {
http
.csrf { it.disable() }
.sessionManagement {
it.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
}
.authorizeHttpRequests { auth ->
auth
.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/api/public/**").permitAll()
.anyRequest().authenticated()
}
.exceptionHandling {
it.authenticationEntryPoint(jwtAuthenticationEntryPoint)
}
.addFilterBefore(
jwtAuthenticationFilter,
UsernamePasswordAuthenticationFilter::class.java
)
return http.build()
}
}4. 인증 컨트롤러
@RestController
@RequestMapping("/api/auth")
class AuthController(
private val authService: AuthService,
private val jwtTokenProvider: JwtTokenProvider
) {
@PostMapping("/login")
suspend fun login(@RequestBody request: LoginRequest): ApiResponse<TokenResponse> {
val authentication = authService.authenticate(
request.email,
request.password
)
val token = jwtTokenProvider.generateToken(authentication)
return ApiResponse.success(
TokenResponse(
accessToken = token,
tokenType = "Bearer",
expiresIn = 3600
)
)
}
}보안 고려사항
- JWT Secret 키 안전한 보관
- Refresh Token 구현
- Token 블랙리스트 관리
- HTTPS 필수 사용