콘텐츠로 이동

bluetape4k-dependencies 1.3.0 활용기 Part 1: 기능 보강과 경계 정리

작은 로봇 작업자들이 projects, exposed, aws, image, text, leader, graph, javers 모듈 블록과 의존성 BOM 보드를 점검하는 3D 작업대 일러스트
BOM 버전을 올리면 커넥션 상태 복원, 캐시 상태, CloudWatch 플러그인, 대용량 파일 I/O, 공급자 런타임 등 여러 경계가 함께 바뀝니다.

bluetape4k-dependencies는 Spring 진영의 spring-boot-dependencies처럼 여러 라이브러리의 의존성 버전을 한곳에서 맞춰 쓰기 위한 BOM입니다. 애플리케이션이나 라이브러리는 BOM 하나를 가져오고, 각 모듈은 같은 버전 집합 위에서 맞물려 동작합니다.

bluetape4k-dependencies 1.3.0으로 올라가면 projects, exposed, aws, image, text, leader, graph, javers의 버전도 함께 변경됩니다. 중요한 것은 버전 숫자 자체가 아닙니다. 실제 적용 시 확인할 질문은 다음과 같습니다.

  • 새로 사용할 수 있는 기능은 무엇인가?
  • 수정된 결함은 무엇인가?
  • 결함이 발생한 원인은 무엇인가?
  • 적용 코드에서는 어떤 경계를 주의해야 하는가?

여기서는 dependencies 내부의 카탈로그 관리 방식보다 각 라이브러리에서 보강한 기능과 설계 경계를 살펴봅니다. 코드와 운영 예시에서 직접 확인할 수 있는 변화에 초점을 맞춥니다.

라이브러리버전주요 변경
projects1.11.0JDBC 트랜잭션 도우미의 Connection 상태 복원 버그 수정
exposed1.11.0캐시 상태 표시기, BigQuery 드라이런, CockroachDB 재시도 도우미
aws0.4.0Ktor CloudWatch/Logs 플러그인, DynamoDB/DAX/IMDS/S3 계열 보강
image0.3.0OCR 예제, Okio 기반 대용량 이미지 I/O
text0.2.1토크나이저와 금칙어 기능을 웹 서비스에서 안전하게 사용하는 예제
leader0.4.0백엔드 예제와 성능 근거 보강, Kubernetes 런타임 충돌 수정
graph0.5.10.5.x 패치 라인 안정화
javers0.2.1JaVers/Exposed 연동의 의존성 경계 정리

graphjavers는 이번 버전에서 변화가 작은 편입니다. 신규 기능 릴리스라기보다 기존 기능을 안정적으로 사용하기 위한 정리에 가깝습니다. 반대로 projects, exposed, aws, image, text, leader에는 서비스 설계에 직접 적용할 수 있는 변화가 있었습니다.

bluetape4k-dependencies 1.3.0 BOM이 여덟 라이브러리 버전과 대표 설계 경계를 함께 정렬하는 구조도
BOM은 버전 번호만 맞추지 않습니다. 각 라이브러리가 보강한 상태 복원, 운영 상태, 수명 주기, 입력·출력, 런타임, 의존성 경계를 하나의 검증 가능한 조합으로 묶습니다.

projects 1.11.0: 트랜잭션 도우미는 빌린 커넥션의 상태를 복원해야 한다

섹션 제목: “projects 1.11.0: 트랜잭션 도우미는 빌린 커넥션의 상태를 복원해야 한다”

먼저 projects입니다. 여기서 가장 먼저 볼 수정은 Connection.withTransaction입니다.

주요 변경 사항

  • Connection.withTransaction이 호출자가 넘긴 Connection 상태를 제대로 복원하지 못하던 문제를 수정했습니다.
  • autoCommit, isolation뿐 아니라 isReadOnly까지 저장하고 되돌리도록 보강했습니다.
  • Exception만 처리하던 실패 경로를 넓혔습니다.
  • rollback과 restore 과정에서 실패를 조용히 묻어두지 않도록 정리했습니다.

트랜잭션 도우미는 단순해 보입니다. autoCommit을 끄고 작업을 실행한 뒤, 실패하면 롤백하고 마지막에 원래 상태를 복원하면 됩니다.

그러나 “원래 상태”의 범위를 정확히 정의해야 합니다. 기존 구현은 autoCommit과 격리 수준을 복원했지만 isReadOnly를 누락했습니다. 실패 처리도 Exception으로 한정했고, 상태 복원 실패는 로그만 남긴 채 지나갈 수 있었습니다.

문제의 모양을 의사코드로 줄이면 이렇게 됩니다.

// 고치기 전 사고방식에 가까운 형태
fun <T> Connection.withTransaction(block: (Connection) -> T): T {
val oldAutoCommit = autoCommit
val oldIsolation = transactionIsolation
autoCommit = false
try {
val result = block(this)
commit()
return result
} catch (e: Exception) {
rollback()
throw e
} finally {
autoCommit = oldAutoCommit
transactionIsolation = oldIsolation
// isReadOnly는 원래 값이 무엇이었는지 모른다.
// 상태 복원 실패를 어떻게 다룰지도 불명확하다.
}
}

새 커넥션을 만들고 테스트가 끝나면 닫는 단위 테스트에서는 이 문제가 잘 드러나지 않습니다. 실제 서비스는 커넥션 풀에서 커넥션을 빌려 쓰므로, 도우미가 상태를 완전히 복원하지 않으면 다음 요청이 그 상태를 이어받습니다.

요청 A
-> 커넥션을 빌림
-> withReadOnlyTransaction 실행
-> isReadOnly 복원 누락
-> 커넥션 풀로 반환
요청 B
-> 같은 커넥션을 다시 빌림
-> 쓰기 작업 실행
-> 읽기 전용 상태 때문에 쓰기 실패

보강 후에는 저장하고 되돌려야 할 상태를 명시적으로 다룹니다.

// 핵심만 줄인 형태
val oldAutoCommit = conn.autoCommit
val oldIsolation = conn.transactionIsolation
val oldReadOnly = conn.isReadOnly
try {
conn.autoCommit = false
return block(conn).also { conn.commit() }
} catch (t: Throwable) {
runCatching { conn.rollback() }.onFailure { t.addSuppressed(it) }
throw t
} finally {
restoreConnectionState(
autoCommit = oldAutoCommit,
isolation = oldIsolation,
readOnly = oldReadOnly,
)
}

JDBC 도우미가 받은 커넥션의 소유자는 호출자입니다. 따라서 autoCommit뿐 아니라 격리 수준, 읽기 전용 상태, 롤백 실패, 상태 복원 실패까지 하나의 계약으로 다뤄야 합니다.

테스트에는 이런 경우를 포함하는 게 안전합니다.

  • 처음부터 autoCommit=false인 커넥션
  • 처음부터 isReadOnly=true인 커넥션
  • 작업 중 Exception이 아닌 실패가 나는 경우
  • 롤백은 성공했지만 상태 복원이 실패하는 경우
  • 읽기 전용 트랜잭션이 끝난 뒤 원래 읽기 전용 상태가 유지되는지 확인하는 경우

도우미의 코드 길이는 영향 범위를 나타내지 않습니다. 호출자가 소유한 커넥션 상태를 변경한다면 성공·실패·복원 실패 경계를 모두 검증해야 합니다.

exposed 1.11.0: 캐시 이상은 운영 상태에 드러나야 한다

섹션 제목: “exposed 1.11.0: 캐시 이상은 운영 상태에 드러나야 한다”

exposed 1.11.0에서는 캐시와 데이터베이스 경계를 보강했습니다.

주요 변경 사항

  • 캐시 일관성 상태 표시기를 추가했습니다.
  • BigQuery 쿼리를 실행하기 전에 드라이런으로 확인할 수 있도록 했습니다.
  • CockroachDB 트랜잭션 재시도 도우미를 보강했습니다.
  • Trino session option처럼 dialect별로 자주 필요한 설정을 다듬었습니다.

캐시를 설계할 때는 보통 읽기 성능부터 고려합니다. DB 조회를 줄이고, 같은 값을 더 빨리 반환하며, write-through나 write-behind로 저장 경로를 정리합니다.

운영 환경에서는 읽기 성능만으로 캐시 상태를 판단할 수 없습니다.

  • write-behind 대기열이 누적되는가?
  • flush 작업이 중단되었는가?
  • 마지막 flush 오류는 무엇인가?
  • 일관성 검사가 실패했는데도 상태가 UP으로 표시되는가?

일관성 보고서 API만으로는 운영자가 상태를 상시 확인하기 어렵습니다. Spring Boot 애플리케이션이라면 동일한 정보를 /actuator/health에 노출해야 합니다.

캐시 장애는 늦게 발견되면 데이터 일관성을 흔들 수 있습니다. 읽기는 계속 빠르게 성공하는 것처럼 끝나는데, 뒤에서 write-behind가 밀리거나 flush가 실패하면 실제 데이터는 이미 어긋날 수 있습니다. 장애가 났는데도 겉으로는 정상처럼 끝납니다. 이런 평화로움은 좋은 징조가 아닙니다. 대개 나중에 더 큰 장애로 돌아옵니다.

그래서 캐시 일관성 상태를 Actuator 상태 정보에 포함했습니다. 상태 표시기는 각 저장소의 CacheHealthReport를 모아 다음 값을 노출합니다.

mapOf(
"mode" to mode.name,
"queueDepth" to queueDepth,
"flushJobRunning" to isFlushJobRunning,
"lastFlushError" to lastFlushError?.message,
)

예를 들어 write-behind 대기열에 아직 반영되지 않은 항목이 남아 있는데 flush 작업이 멈췄다면 상태는 OUT_OF_SERVICE로 내려갈 수 있습니다.

{
"status": "OUT_OF_SERVICE",
"details": {
"repositoryCount": 1,
"reports": [
{
"mode": "WRITE_BEHIND",
"queueDepth": 3,
"flushJobRunning": false,
"lastFlushError": null
}
]
}
}

flush 자체가 실패했다면 DOWN으로 판단하고 마지막 실패 메시지도 함께 제공합니다.

{
"status": "DOWN",
"details": {
"repositoryCount": 1,
"reports": [
{
"mode": "WRITE_BEHIND",
"queueDepth": 1,
"flushJobRunning": true,
"lastFlushError": "planned write-behind flush failure"
}
]
}
}

형태는 단순한 상태 검사지만 운영에서는 장애 발견 시간을 좌우합니다.

사용자 요청
-> 캐시 쓰기 성공
-> 백그라운드 flush 실패
-> queueDepth 증가 / lastFlushError 기록
-> /actuator/health 에서 DOWN 또는 OUT_OF_SERVICE
-> 운영자가 DB 반영 지연을 확인

BigQuery 드라이런도 같은 원칙을 따릅니다. 쿼리를 실제로 실행하기 전에 유효성과 예상 비용을 확인하면 운영 쿼리를 실행한 뒤에야 오류를 발견하는 일을 줄일 수 있습니다. CockroachDB 재시도 도우미는 직렬화 가능한 트랜잭션에서 SQLSTATE 40001처럼 재시도가 허용된 실패만 선별해야 합니다.

repeat(maxAttempts) { attempt ->
try {
return transaction { updateAccountBalance() }
} catch (e: SQLException) {
if (e.sqlState != "40001" || attempt == maxAttempts - 1) {
throw e
}
delay(backoff(attempt))
}
}

캐시 상태 표시와 재시도는 문제를 숨기는 기능이 아닙니다. 이상 상태를 조기에 드러내고, 재시도가 허용된 실패만 안전하게 처리하는 운영 장치입니다.

aws 0.4.0: CloudWatch 플러그인은 애플리케이션 수명 주기를 침범하지 않아야 한다

섹션 제목: “aws 0.4.0: CloudWatch 플러그인은 애플리케이션 수명 주기를 침범하지 않아야 한다”

aws 0.4.0은 여러 AWS 통합 기능을 추가한 릴리스입니다.

주요 변경 사항

  • Ktor CloudWatch/Logs 플러그인을 추가했습니다.
  • DynamoDB Ktor 통합과 선택적 DAX 구성을 보강했습니다.
  • IMDS 도우미, S3 Access Grants, S3 Vectors 관련 API를 확장했습니다.
  • SQS/S3 관측 정보를 Micrometer와 연동하는 경로를 정리했습니다.

Ktor에서 메트릭과 로그를 CloudWatch로 전송하는 기능 자체는 단순해 보입니다. 그러나 실제 구현에서는 전송 코드보다 자원 소유권과 종료 동작을 더 엄격하게 정의해야 합니다.

플러그인의 수명 주기 계약은 다음과 같습니다.

  • 기본값으로는 아무것도 보내지 않습니다.
  • 사용자가 주입한 AWS 클라이언트는 플러그인이 닫지 않습니다.
  • 플러그인이 직접 만든 클라이언트만 애플리케이션 종료 시점에 닫습니다.
  • 종료 시 flush는 정해진 시간 안에 끝냅니다.
  • 코루틴 취소를 삼키지 않습니다.
  • 전역 로깅 설정을 암묵적으로 변경하지 않습니다.

클라우드 통합 기능은 애플리케이션 수명 주기와 맞닿아 있습니다. 종료 시 프로세스를 지연시키거나, 호출자가 소유한 클라이언트를 닫거나, 로컬 개발 환경에서 의도하지 않은 AWS 연결을 시도해서는 안 됩니다.

사용 측 코드는 다음과 같이 구성할 수 있습니다.

install(CloudWatchKtorPlugin) {
namespace = "OrderService"
batchSize = 100
// 외부에서 주입한 클라이언트는 플러그인이 닫지 않는다.
cloudWatchAsyncClient = sharedCloudWatchClient
}
routing {
post("/orders") {
val order = call.receive<CreateOrderRequest>()
application.cloudWatch().putMetricDatum(
metricName = "OrderCreated",
value = 1.0,
unit = StandardUnit.COUNT,
)
call.respond(HttpStatusCode.Accepted)
}
}

CloudWatch Logs도 같은 계약을 따릅니다. 플러그인이 전역 로깅 appender를 교체하지 않고, 필요한 이벤트를 버퍼에 명시적으로 추가한 뒤 정해진 시점에 flush합니다.

Ktor 라우트
-> CloudWatchLogs 런타임에 이벤트 추가
-> batchSize 또는 flush 시점 도달
-> PutLogEvents 호출
-> 애플리케이션 종료 시 제한된 타임아웃 안에서 마지막 flush

이 기능은 Ktor 서비스의 전역 로깅 체계를 바꾸지 않고 필요한 메트릭과 로그 이벤트만 CloudWatch로 보낼 때 사용합니다. 클라우드 연동을 추가할 때는 다음 질문을 먼저 확인해야 합니다.

“이 기능이 대신 관리하는 자원은 무엇이며, 그 소유 권한은 적절한가?”

AWS 연동은 권한, 비용, 네트워크, 종료 시점을 함께 다룹니다. 따라서 전송 성공뿐 아니라 플러그인이 소유하지 않은 자원과 전역 설정을 변경하지 않는지도 검증해야 합니다.

image 0.3.0: OCR보다 먼저 파일 크기를 확인해야 한다

섹션 제목: “image 0.3.0: OCR보다 먼저 파일 크기를 확인해야 한다”

image 0.3.0은 OCR 예제와 대용량 이미지 I/O 경계를 보강했습니다.

주요 변경 사항

  • images-ocr 사용 예제를 추가했습니다.
  • 기본 예제, Spring Boot, Ktor에서 이미지를 읽고 텍스트를 추출하는 흐름을 보여줍니다.
  • 언어 선택과 페이지 분할 옵션을 예제에서 확인할 수 있습니다.
  • 대용량 이미지 I/O를 위해 Okio Source/Sink 기반 경로를 보강했습니다.

OCR은 이미지에서 글자를 추출하므로 기능을 이해하기 쉽습니다. 그러나 실제 서비스 요청은 OCR보다 먼저 파일 I/O 경계를 통과합니다.

작은 이미지 예제에서는 ByteArray 중심 API가 편리합니다. 하지만 300KB 예제와 30MB 스캔 파일은 JVM 힙에 전혀 다른 부하를 줍니다.

그래서 0.3.0에서는 Okio Source/Sink 기반 경로를 보강했습니다. 파일 전체를 메모리에 일괄 적재하는 방식에만 의존하지 않기 위해서입니다. OCR 전처리, 썸네일 생성, 업로드·다운로드 흐름에서는 이 차이가 메모리 사용량을 좌우합니다.

// 작은 예제에서는 편하다.
val bytes: ByteArray = Files.readAllBytes(path)
val text = ocr.extractText(bytes)
// 대용량 파일을 처리하는 서비스에서는 스트리밍 경계를 우선 검토한다.
FileSystem.SYSTEM.source(path).use { source ->
FileSystem.SYSTEM.sink(output).use { sink ->
imageIo.resize(source, sink, width = 1200)
}
}

서비스 처리 흐름은 다음과 같이 달라집니다.

전체 적재 흐름
업로드 -> ByteArray 전체 로딩 -> 크기 조정/OCR -> ByteArray 응답
스트리밍 경계 적용 흐름
업로드 -> Source로 읽기 -> 백엔드 처리 -> Sink로 쓰기

Source를 사용해도 모든 메모리 문제가 사라지지는 않습니다. Scrimage나 libvips는 디코딩·인코딩 단계에서 버퍼를 확보할 수 있습니다. 따라서 문서에는 스트리밍으로 줄일 수 있는 메모리와 백엔드 특성상 필요한 버퍼를 구분해 설명해야 합니다.

이미지/OCR 기능을 추가할 때는 옵션보다 파일의 소유권과 메모리 적재 지점을 먼저 점검해야 합니다. 파일을 여는 위치, 닫는 주체, 전체 디코딩이 발생하는 단계를 명시하면 대용량 입력의 위험을 줄일 수 있습니다.

text 0.2.1: 토크나이저 API에는 입력 길이 정책이 필요하다

섹션 제목: “text 0.2.1: 토크나이저 API에는 입력 길이 정책이 필요하다”

text 0.2.1은 알고리즘 교체보다 웹 서비스 입력 경계와 오류 처리 보강에 초점을 둔 릴리스입니다.

주요 변경 사항

  • 실행 가능한 text-search 예제를 보강했습니다.
  • Lingua 감지기 재사용과 임계값 동작을 테스트로 검증했습니다.
  • 토크나이저·금칙어 웹 서비스 안전 예제를 추가했습니다.
  • 긴 입력, 검증 실패, 오류 응답에서 주의할 부분을 문서화했습니다.

라이브러리 수준의 토크나이저는 문자열을 입력받아 토큰을 반환합니다. 그러나 REST API에 노출하면 입력 길이, 원문 노출, 오류 응답이 서비스 계약이 됩니다.

웹 API의 입력 경계는 다음과 같이 정의할 수 있습니다.

private const val MAX_TEXT_LENGTH = 20_000
post("/tokenize") {
val request = call.receive<TokenizeRequest>()
if (request.text.length > MAX_TEXT_LENGTH) {
call.respond(
HttpStatusCode.PayloadTooLarge,
mapOf("message" to "text is too long", "limit" to MAX_TEXT_LENGTH),
)
return@post
}
val tokens = tokenizer.tokenize(request.text)
call.respond(TokenizeResponse(tokens = tokens))
}

여기서 조심할 부분은 실패 응답에 원문을 넣지 않는 것입니다.

{
"message": "text is too long",
"limit": 20000
}

다음처럼 원문을 반환하면 구현은 간단하지만 민감한 정보가 노출될 수 있으므로 피해야 합니다.

{
"message": "text is too long: 주민등록번호가 포함된 긴 원문..."
}

공개 라이브러리의 예제는 각 서비스가 입력 길이, 오류 응답, 로그 정책을 임의로 구현하지 않도록 안전한 기본 형태를 보여주어야 합니다. 이번 보강은 토크나이저 알고리즘보다 긴 입력 제한, 400/413 상태 코드 매핑, 원문 노출 방지라는 서비스 경계를 다룹니다.

leader 0.4.0: 리더 공급자 선택은 런타임 조합까지 포함한다

섹션 제목: “leader 0.4.0: 리더 공급자 선택은 런타임 조합까지 포함한다”

leader 0.4.0에서는 백엔드 예제와 성능 근거를 보강했습니다.

주요 변경 사항

  • Redis, SQL, Kubernetes, Consul, etcd, DynamoDB 백엔드 예제를 정리했습니다.
  • 백엔드 선택에 참고할 수 있는 성능 근거를 보강했습니다.
  • Kubernetes K3s 테스트 런타임 충돌을 수정했습니다.

분산 리더 선출은 알고리즘만 선택해서 끝나지 않습니다. Redis, SQL, Kubernetes Lease 중 무엇을 사용하는지에 따라 장애 감지 방식, 운영 도구, 테스트 런타임, 의존성이 달라집니다. 따라서 예제와 벤치마크도 공급자별 경계를 보여주어야 합니다.

이번 수정에서 문제가 된 부분도 Kubernetes 공급자가 가져온 런타임 의존성이었습니다.

NoSuchMethodError: io.vertx.ext.web.client.WebClientOptions.setMaxPoolSize(int)

리더 선출 테스트가 Vert.x 메서드를 찾지 못해 실패했습니다. Kubernetes 공급자는 Fabric8 Kubernetes 클라이언트를 사용하고, Fabric8은 다시 Vert.x 런타임과 결합합니다. 공급자 하나를 선택해도 실제로는 그 공급자가 가져오는 스토리지와 런타임 조합까지 함께 선택하게 됩니다.

Fabric8 Kubernetes 클라이언트 7.7.0은 Vert.x 4 web-client API를 기대하지만 테스트 런타임 클래스패스에는 Vert.x 5가 올라올 수 있었습니다. 최신 버전 여부보다 함께 사용하는 라이브러리의 호환 버전 조합이 중요합니다.

이 문제는 코드만으로 확인하기 어렵습니다. 실제 의존성 그래프를 조회해야 합니다.

Terminal window
./gradlew :bluetape4k-leader-k8s:dependencyInsight \
--configuration k8sTestRuntimeClasspath \
--dependency vertx-web-client

의도한 상태는 다음과 같은 형태입니다.

K3s 테스트 런타임
-> fabric8-kubernetes-client 7.7.0
-> Vert.x 4 web-client API 필요
-> vertx-web-client 4.x
-> k8sTest 성공

Vert.x 5가 선택되면 테스트는 리더 선출을 검증하기 전에 런타임 메서드 불일치로 실패합니다. Kubernetes 백엔드를 선택할 때는 잠금 저장소뿐 아니라 공급자가 가져오는 클라이언트와 런타임 버전 조합까지 확인해야 합니다.

graph와 javers: 패치 릴리스는 의존성 경계를 안정화한다

섹션 제목: “graph와 javers: 패치 릴리스는 의존성 경계를 안정화한다”

graphjavers도 이번 dependencies 1.3.0에 포함됩니다.

주요 변경 사항

  • graph 0.5.1: 0.5.x 패치 라인을 안정적으로 소비합니다.
  • javers 0.2.1: JaVers/Exposed 연동에서 의존성 경계를 정리한 패치 릴리스입니다.

graph 0.5.1을 설명할 때 다음 기능선의 내용을 포함하면 현재 릴리스의 범위가 흐려집니다. 청크 단위 그래프 내보내기 커서 API는 0.6.0 기능선에 속하며, dependencies 1.3.0이 정렬한 버전은 0.5.1입니다.

javers도 비슷합니다. 큰 기능은 0.2.0에서 javers-exposed, javers-ddd, DDD workshop example로 들어왔고, 0.2.1은 Exposed BOM 경계를 Gradle implementation 범위에 맞춰 정리한 패치 릴리스입니다.

이 변경은 새 API를 추가하지 않지만 소비자의 클래스패스에 직접 영향을 줍니다. 내부 구현 의존성이 외부로 노출되지 않도록 하고, BOM이 검증한 패치 라인을 유지하면 소비자의 의존성 그래프를 더 안정적으로 관리할 수 있습니다.

Gradle 의존성으로 보면 차이가 더 분명합니다.

// 소비자가 직접 써야 하는 API라면 노출될 수 있다.
api("io.github.bluetape4k:javers-exposed")
// 내부 구현에만 필요하다면 외부에 노출하지 않는다.
implementation("org.jetbrains.exposed:exposed-core")

확인할 부분은 새 기능의 개수가 아닙니다. BOM을 적용했을 때 프로젝트의 의존성 그래프가 불필요하게 확장되지 않는지, 현재 안정화된 패치 라인과 다음 기능선을 구분하고 있는지 점검해야 합니다.

dependencies 1.3.0을 적용할 때 점검할 내용은 다음과 같습니다.

  • JDBC 도우미를 직접 만들거나 감싼다면 Connection의 원래 상태를 어디까지 복원해야 하는지 확인합니다.
  • write-behind 캐시를 사용한다면 /actuator/health에서 queueDepth, flushJobRunning, lastFlushError를 확인할 수 있어야 합니다.
  • Ktor에 CloudWatch/Logs를 연결할 때는 플러그인이 AWS 클라이언트와 애플리케이션 수명 주기를 어디까지 관리하는지 확인합니다.
  • 이미지/OCR 기능을 추가할 때는 OCR 옵션보다 파일이 메모리에 적재되는 지점을 먼저 점검합니다.
  • 토크나이저·금칙어 API를 REST 엔드포인트에 노출한다면 입력 길이 제한과 오류 응답의 원문 노출 여부를 먼저 정합니다.
  • Kubernetes 공급자처럼 클라이언트와 런타임 의존성이 얽힌 백엔드는 dependencyInsight로 실제 클래스패스를 확인합니다.
  • graph, javers처럼 변화가 작은 패치 라인도 의존성 그래프를 안정적으로 유지하는 데 의미가 있습니다.

이 글에서 다룬 변화는 기능 목록보다 서비스 경계를 설명합니다. 새 기능을 적용하기 전에 자원 소유권, 상태 복원, 입력 크기, 오류 노출, 런타임 호환성을 먼저 확인하면 같은 유형의 결함을 반복하지 않을 수 있습니다.

버전 정렬과 배포 절차는 다음 글에서 별도로 다룹니다. Maven Central에 게시한 아티팩트는 되돌릴 수 없으므로 기능 검증과 다른 배포 경계가 필요합니다.

처음 bluetape4k-dependencies를 가져오는 방법부터 보고 싶다면 사용 가이드를 먼저 읽으면 됩니다.

댓글

GitHub 계정으로 의견을 남기거나 reaction을 남길 수 있습니다.