5.1 KiB
5.1 KiB
title, source_type, status, related_branches, related_projects, tags, created, status_label
| title | source_type | status | related_branches | related_projects | tags | created | status_label | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| interview-prep / operational-error-envelope-and-observability-foundation | interview-prep | raw |
|
|
|
2026-06-01 | collecting |
interview-prep: operational-error-envelope-and-observability-foundation
Layer:
raw/interviews/— 면접 질문 원본 수집·연구 노트. 다듬어진 답변은/interviewize후wiki/interview/에 별도 작성.
Parent / 부모
- raw/branch-notes/feature-operational-error-observability-foundation — 운영 실패 분류 enum(10-category) + 응답 envelope
meta/error.category+ snake_case MDC + inbound 헤더 sanitization 을 구현·검증한 결정/근거. - raw/project-notes/ca-skeleton-operational-contract — ca-tmpl 의 운영 계약 SSOT(§3 응답 envelope, §6 error category, §8 structured log).
질문 / Question
후보 질문 묶음 (실제 면접에서 받은 것 아님 — 본 작업에서 정직하게 도출):
- 응답 포맷을 RFC 7807 ProblemDetail 대신 자체 envelope 으로 가져갔다고 했는데, 이미 운영 중인 envelope 에
error.category와meta객체를 기존 계약을 깨지 않고 어떻게 추가했나요? - 같은 식별자가 로그에선
request_id(snake), JSON 응답에선meta.requestId(camel), HTTP 헤더에선X-Request-Id(kebab) 로 다르게 나오는데, 이게 버그가 아니라 의도된 설계라는 걸 어떻게 보장하나요? - 클라이언트가 보낸
X-Request-Id헤더를 로그에 남길 때 어떤 보안 문제가 있고 어떻게 막았나요? retryable을 category 로 계산하지 않고 per-code 로 둔 이유는?
질문 의도 추론 / Why this question
- 핵심 평가 대상:
- 하위호환 확장: 운영 중인 직렬화 계약에 필드를 additive 로 추가하는 감각 (record 컴포넌트 추가 시 모든 호출부/테스트가 깨지는 blast radius 를 어떻게 통제했는가 — 본 작업에선
PortfolioErrorCode/BulkEnvelopeTest같은 숨은 consumer 까지 빌드로 잡아냄). - 표현 계층 분리: 동일 논리 식별자의 case 표현이 계층(MDC/JSON/HTTP/W3C)마다 다른 게 관례임을 알고, 매핑을 SSOT(registry)로 고정해 drift 를 막는 인식.
- 보안 기본기: CWE-117 log injection / log forging 을 구조화 JSON 로깅 전제 에서 어떻게 다르게 다루는지 (CR/LF·제어문자 strip vs reject vs encode 의 trade-off).
- 계약 vs 런타임 분리: category 는 식별(문서/메트릭 차원)이고 retryable 은 per-code 런타임 신호라는 책임 분리 인식.
- 하위호환 확장: 운영 중인 직렬화 계약에 필드를 additive 로 추가하는 감각 (record 컴포넌트 추가 시 모든 호출부/테스트가 깨지는 blast radius 를 어떻게 통제했는가 — 본 작업에선
- 함정 / 흔히 빠지는 답변 패턴:
- "envelope 만들었다"로 끝내고 왜 ProblemDetail 을 거부했는지(success/error 대칭 + retryable 1급 + 표준 lock-in 회피)와 그 trade-off(표준 호환성 손실)를 말 못함.
- snake↔camel↔kebab 을 "그냥 컨벤션"이라 하고 단일 case 로 통일하면 왜 안 되는지(HTTP/W3C/JSON 관례 충돌)를 설명 못함.
- log injection 을 "입력 검증"으로 뭉뚱그리고 구조화 로깅에선 위협이 줄 위조(CR/LF) 라는 점, strip 의 한계(필드 smuggling/길이 폭주는 length cap 으로 별도 처리)를 모름.
- retryable 을 category default 로 계산한다고 답해
INTERNAL_ERROR(retryable=true)같은 per-code 예외를 설명 못함.
- 따라올 만한 후속 질문:
- 인터페이스에 추상 메서드(
category())를 추가했을 때 다운스트림 enum 이 전부 깨지는데, 이걸 컴파일러로 강제하는 게 장점인가 단점인가? meta.traceId가 tracing 비활성 환경에서도 비면 안 된다고 했는데(D7) 어떻게 보장하나? (generated opaque id fallback)- 이 계약 테스트를
app-bootstrap풀 컨텍스트가 아니라 adapter 모듈 standalone MockMvc 로 옮긴 이유는? (→ raw/errors/webmvctest-nested-springbootconfiguration-context-pollution-2026-06-01)
- 인터페이스에 추상 메서드(
답변 뼈대 / Answer skeleton (raw)
- ProblemDetail 거부 = success/error 대칭 +
retryable/category1급화 + 표준 lock-in 회피. trade-off = RFC 표준 호환성 포기(의식적). - additive 확장 =
error.category(필드 추가),meta(flattraceId→객체) 모두 boundary D5/D6(대칭/ProblemDetail 거부)을 불변으로 두고 위에 얹음. 깨지는 consumer 는 컴파일러가 전부 노출 → 한 패스로 마이그레이션. - 식별자 매핑 = registry(mdc-keys.yaml/headers.yaml)에
mdc_key/envelope_meta_field/header name 3열을 1:1 로 등록, 변환 지점은ResponseMetaFactory.fromMdc()단일화(snake→camel). - log injection = 구조화 JSON 로깅 전제 → CR/LF/제어문자(
<0x20) strip + length cap, reject/encode 아님(값 보존, 줄 위조만 차단).