18. cache-aside 쓰기 순서: 커밋 전 캐시 반영과 무효화 누락 (C#)

난이도 하 해설 보기 →

결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커 (A)(B) 는 주목 위치 힌트다.

결함 코드 · C#
// 시나리오: 플레이어 프로필 캐시(cache-aside) — 읽기 캐시 + DB 원본
//
// 프로필(닉네임, 소개글 등)은 읽기가 매우 잦아 Redis 같은 캐시를 앞에 둔다.
// 읽기: 캐시 히트면 캐시 값, 미스면 DB에서 읽어 캐시에 채운다.
// 쓰기: 프로필을 수정하면 DB와 캐시를 갱신한다.
//
// 요구사항:
//  - 커밋에 성공한 값만 이후 읽기에 보여야 한다(커밋 안 된/롤백된 값이 캐시로
//    새어나가면 안 된다).
//  - DB 갱신이 실패하면 캐시가 그 실패한 값을 계속 서빙하면 안 된다.
//  - 읽기·쓰기는 여러 스레드/요청에서 동시에 일어난다.
//
// 아래 리포지토리의 (A)(B) 지점을 검토하라.

using System;

public interface ICache
{
    bool TryGet(string key, out string value);
    void Set(string key, string value);
    void Remove(string key);
}

public interface IDb
{
    string Read(string key);
    void Update(string key, string value);   // 실패 시 예외
}

public sealed class ProfileRepository
{
    private readonly ICache _cache;
    private readonly IDb _db;
    public ProfileRepository(ICache cache, IDb db) { _cache = cache; _db = db; }

    public string GetProfile(string playerId)
    {
        if (_cache.TryGet(playerId, out var cached))
            return cached;

        var value = _db.Read(playerId);
        _cache.Set(playerId, value);
        return value;
    }

    public void UpdateProfile(string playerId, string newValue)
    {
        _cache.Set(playerId, newValue);      // (A)
        _db.Update(playerId, newValue);      // (B)
    }
}
내 리뷰 · C#
내 답안 · 자동 저장

작성 후 위 해설 보기에서 모범 해설과 대조하세요.