30. 길드 가입 신청 수락의 동시 처리 (이중 소속 / 정원 초과)

난이도 하 해설 보기 →

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

결함 코드 · C#
// ============================================================================
// [코드리뷰 문제] C# - 길드 가입 신청 수락이 여러 길드에서 동시에 일어나는 상황
// ----------------------------------------------------------------------------
// 시나리오 (커뮤니티/길드):
//   - 한 플레이어는 여러 길드에 동시에 가입 "신청"을 넣어 둘 수 있다.
//   - 각 길드의 간부가 신청 목록을 보고 "수락"을 누르면 그 플레이어가 길드에 들어온다.
//   - 규칙: 한 플레이어는 동시에 한 길드에만 소속될 수 있고, 길드 정원을 넘기면 안 된다.
//
// 상황:
//   - 인기 신청자 A 가 길드 G1, G2 두 곳에 신청해 두었다.
//   - G1 간부와 G2 간부가 거의 같은 순간에 각자 A 의 신청을 "수락"한다.
//   - AcceptApplication 은 서로 다른 스레드(요청)에서 동시에 호출될 수 있다.
//
// 과제:
//   이 코드의 잠재적 문제를 모두 찾고, 두 수락이 동시에 들어왔을 때 A 의 소속과 각 길드의
//   인원/신청 목록이 어떤 상태가 되는지 설명하라. 수정안과 더 나은 설계를 제시하라.
//   (먼저 직접 리뷰를 적은 뒤 answer.md 와 대조할 것)
// ============================================================================

using System.Collections.Generic;

public class Guild
{
    public long Id;
    public int  Capacity;
    public List<long> Members = new();
}

public interface IGuildRepo
{
    Guild Get(long guildId);
    long? GetPlayerGuild(long playerId);          // 소속 길드 id, 없으면 null
    void  AddMember(long guildId, long playerId);
    void  RemoveApplication(long playerId, long guildId);
}

public class GuildService
{
    private readonly IGuildRepo _repo;
    public GuildService(IGuildRepo repo) { _repo = repo; }

    // 길드 간부 요청으로 호출. 서로 다른 길드에서 같은 신청자에 대해 동시 호출될 수 있다.
    public bool AcceptApplication(long guildId, long playerId)
    {
        if (_repo.GetPlayerGuild(playerId) != null)      // (A) 이미 다른 길드 소속인지
            return false;

        var g = _repo.Get(guildId);
        if (g.Members.Count >= g.Capacity)               // (B) 정원 확인
            return false;

        _repo.AddMember(guildId, playerId);              // (C) 소속 반영
        g.Members.Add(playerId);
        _repo.RemoveApplication(playerId, guildId);      // (D) 이 길드 신청만 정리
        return true;
    }
}
내 리뷰 · C#
내 답안 · 자동 저장

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