반응형

AI와 mcp를 써보고, 느낀 점을 적어보았습니다.

앞으로는 잘 정리된 히스토리(문서)가 개발에서 가장 중요한 자산이지 않을까 생각됩니다.

문서화 기반 개발(Document-Driven Development)

문서화 기반 개발이란 말 그대로 문서를 중심으로 요구사항 도출, 디자인, 개발, 테스트를 하나의 피드백 루프로 통합하는 접근 방식입니다. 기존의 코드 중심 개발(Code-Driven Development)과 달리 개발의 진입점(entry point)이 문서입니다. 팀은 문서를 작성하며 시스템의 동작을 정의하고, 이 문서가 곧바로 설계 명세서가 되며, 나아가 테스트의 기준선 역할까지 수행합니다.

 

문서가 곧 팀의 공통 언어이자 설계서이고, 또 코드에 대한 검증 기준이 되는 셈입니다. 잘 정립된 문서는 개발자, 디자이너, 기획자 모두가 바라보는 하나의 진실된 소스(source of truth)로 기능하며, 문서에 쓰인 대로 시스템이 동작하도록 코드를 구현하고 테스트까지 진행하게 됩니다. 이런 사이클에서는 문서와 코드의 괴리가 줄어들고, 문서만 읽어도 현재 시스템이 무엇을 하는지 이해할 수 있게 됩니다.

문서화가 어려운 이유

그렇다면 왜 현실에서는 문서화 기반 개발이 잘 이루어지지 않을까요? 문서화가 어려운 대표적인 이유 몇 가지를 짚어보겠습니다:

  1. 문서도 유지보수가 필요한 “소프트웨어”다 – 코드에 리팩터링이 필요하듯 문서에도 지속적인 업데이트와 구조 개선이 필요합니다. 하지만 많은 조직에서는 코드 리팩터링에는 공을 들이면서도 문서 리팩터링에는 거의 리소스를 할애하지 않습니다. 시간이 지날수록 코드와 문서의 불일치가 커지고, 문서는 신뢰를 잃게 됩니다.
  2. 문서는 이타적인 행위다 – 문서 작성은 당장 개인의 성과로 드러나기보다는 팀 전체를 위한 공유 행위입니다. 업무에 쫓기는 환경에서는 개발자가 기능 구현이나 버그 수정처럼 눈앞의 일에 집중하게 되고, 문서 작성은 우선순위에서 밀려나기 쉽습니다. 특히 빠른 결과를 요구하는 비즈니스 환경에서는 문서가 쉽게 뒷전으로 밀려나 결국 내용이 오래되기 쉽습니다.
  3. 문서보다 비즈니스가 더 빠르다 – 요즘 같은 빠른 실험과 MVP 중심 개발 문화에서는 문서화 속도가 비즈니스 변화를 따라가기 어렵습니다. 제품은 수시로 피벗하고 기능은 계속 바뀌는데, 그때마다 문서를 모두 수정하기란 현실적으로 버겁습니다. 결국 문서는 실제 제품보다 항상 한 발 뒤처지게 되죠.

    이러한 문제를 해결하려면, 사람의 수동적인 노력만으로는 한계가 있고 자동화된 문서화 시스템이 필수적입니다.

MCP를 통한 문서 자동화 시스템

이 자동화된 문서화 시스템의 한 예로 떠오르는 것이 바로 MCP(Multi-Context Protocol)입니다. MCP는 Anthropic이 2024년에 제안한 새로운 표준으로, 요약하면 다양한 소프트웨어 툴과 AI를 연결해주는 프로토콜입니다

 

Notion, Jira, Google Sheets, Figma처럼 서로 다른 플랫폼들의 문서를 AI 에이전트가 읽고 요약하거나 서로 연결할 수 있게 해주는 통합 규약이라고 볼 수 있습니다. 한마디로 여러 곳에 흩어진 문서와 데이터를 한곳에 모아 활용할 수 있게 만드는 문맥 통합 도구입니다.

 

Notion → MCP (Notion MCP Server)
  ↓ 
Jira → MCP (Jira MCP Server)
   ↓ 
Figma → MCP (Figma MCP Server)
   ↓ 
cursor Agent

 

위의 흐름은 MCP를 활용한 문서 자동화의 단순 예시입니다.

 

각각의 도구(Figma, Notion, Jira 등)가 자신만의 MCP 서버로 열려 있다고 가정하면,

 

AI 에이전트나 통합 스크립트가 이들을 차례차례 호출하여 요구사항 → 티켓 → 코드 -> 테스트 코드를 자동으로 엮어낼 수 있습니다. 곧 요구사항 문서가 디자인과 코드 생성으로 이어지고, 작업 완료 시 Jira 티켓이나 노션 페이지의 상태가 자동 갱신되는 등 문서→개발→피드백의 루프가 자동화될 수 있음을 보여줍니다.

 

문서 → 디자인 → 개발 → 테스트 → 피드백 사이클

앞서 언급한 자동화 루프를 조금 더 구체적으로 살펴보겠습니다. 문서화 기반 개발 사이클에서는 문서 작성부터 디자인 시안, 코드 구현, 테스트, 그리고 다시 문서 갱신까지가 하나의 흐름으로 이어집니다. 이를 단계별로 나타내면 다음과 같습니다

 

 

요구사항 문서가 변경되면, 그 내용이 Figma에 반영되고, 디자인이 확정되면 코드 저장소에 해당 컴포넌트나 코드 스켈레톤이 생성됩니다.

 

개발자가 그 코드를 구현하면 CI 상에서 테스트 코드가 돌아가고, 여기에는 MSW(Mock Service Worker)로 구현한 가짜 API 서버까지 포함하여 통합 테스트가 실행됩니다. 모든 테스트가 통과하면 그 결과가 다시 노션 문서나 Jira 티켓에 자동으로 댓글로 남는다든지 상태를 “완료”로 변경한다든지 하는 식으로 문서와 티켓이 최신화됩니다.

 

이렇게 함으로써 문서의 변경 → 코드 변경 → 테스트 → 문서 갱신의 순환 고리가 자동으로 돌아가게 됩니다. 결국 문서가 변경되면 코드와 테스트 결과로 증명되고, 테스트가 실패하면 문서나 코드 중 어딘가 잘못된 부분을 알려주며, 코드 변경도 문서에 자동 기록되는 생태계가 만들어지는 것입니다.

 

이 순환 구조의 핵심은, 문서와 코드, 테스트가 동등한 1급 시민으로 취급된다는 점입니다. 어느 하나라도 변경되면 나머지 둘이 이를 검증하고 보완해주는 삼각형 구조라고 볼 수 있습니다. 이러한 체계에서는 문서도 항상 최신의 기능을 반영하게 되고, 팀원 누구든 문서를 보면 현재 시스템의 동작과 일치하는 내용을 접하게 됩니다.

 

테스트 코드도 문서다

테스트 코드는 개발자가 기대한 시스템의 동작을 코드로 서술한 것으로, 일종의 “실행 가능한 문서”입니다. 예를 들어 사용자의 로그인 후 동작을 다음과 같이 테스트 코드로 명세할 수 있습니다. 또한, 테스트 코드는 개발자가 기대한 시스템의 동작을 코드로 서술한 문서이며 AI로 만든 산출물에게 바로 강력한 피드백을 줄 수 있는 방법입니다.   
즉, 테스트는 “읽히는 문서”이면서 동시에 “실행 가능한 명세(Executable Specification)”입니다.

// 테스트 코드도 문서다.
test("사용자는 로그인 후 대시보드로 이동해야 한다", async () => {
  const response = await login(user);
  expect(response.redirect).toBe("/dashboard");
});

 

위 테스트는 자연어 문장(테스트 설명)과 코드 구현이 결합되어 시스템의 요구사항을 스스로 검증합니다. 테스트 설명 부분을 보면 마치 사양서의 한 문장처럼 “사용자는 로그인 후 대시보드로 이동해야 한다”라고 적혀 있습니다. 이 문장은 해당 기능의 요구사항을 나타내는 문서 역할을 하고, 아래의 코드 구현부는 실제 로그인 함수 login(user)의 반환값(response.redirect)이 기대한 대로 “/dashboard”인지 확인함으로써 그 문서의 내용을 검증합니다.

문서가 “무엇을 해야 하는지” 설명한다면, 테스트는 “정말 그렇게 되는지”를 증명합니다
다시 말해, 문서가 코드의 그림자라면 테스트 코드는 그 그림자의 진위를 증명하는 거울과도 같습니다. 테스트가 통과하지 못한다는 것은 곧 해당 기능에 대한 문서(또는 코드)가 실제 동작과 어긋남을 의미하므로, 테스트 실패를 통해 우리는 문서가 낡았거나 코드에 결함이 있음을 즉시 알아낼 수 있습니다. 이처럼 잘 작성된 테스트 코드는 팀에게 시스템의 신뢰성을 제공함과 동시에, 현재 시스템이 문서대로 작동하고 있음을 보여주는 살아있는 증거가 됩니다.

 

🧪 MSW를 통한 통합 테스트 기반 피드백

그렇다면 앞서 예로 든 테스트 코드에서 실제 API 호출이나 외부 서비스와의 통신은 어떻게 다룰까요?

여기서 등장하는 것이 바로 MSW(Mock Service Worker)입니다.

 

MSW는 브라우저나 Node 환경에서 서비스 워커 API를 활용하여 실제 네트워크 요청을 가로채고, 개발자가 정의한 모의 응답(Mock response)을 반환해주는 라이브러리입니다. 이를 이용하면 별도의 테스트용 서버를 띄우지 않고도 네트워크 계층을 포함한 통합 테스트를 손쉽게 구현할 수 있습니다. 다시 말해, 프론트엔드 관점에서 클라이언트-서버 간의 상호작용 전체를 테스트 코드에서 재현할 수 있게 됩니다.

 

예를 들어 “사용자가 로그인에 성공하면 토큰을 로컬스토리지에 저장한다”는 시나리오를 테스트하려 한다면, MSW로 로그인 API의 응답을 가로채어 성공 케이스를 미리 정의해둘 수 있습니다. 아래 코드는 MSW로 가짜 로그인 API 핸들러를 만들고, 이를 테스트에서 사용하는 예시입니다:

 

// 로그인 API 성공 응답 핸들러 정의
export const createLoginSuccessHandler = (mockTokenResponse: TokenResponse) => {
  return http.post(`${API_BASE_URL}${AUTH_ROUTES.LOGIN}`, async ({ request }) => {
    const body = await request.json();
    // ... 요청 바디 검증 로직 등이 들어갈 수도 있음
    return HttpResponse.json<ApiResponse<TokenResponse>>({
      code: API_RESPONSE_CODES.OK,
      message: "정상적으로 처리되었습니다.",
      data: mockTokenResponse,
    });
  });
};

// 테스트 시나리오 구현 (Jest + Testing Library 예시)
describe("when 유효한 이메일을 입력하고 로그인 버튼을 클릭할 때", () => {
  it("to be: 로그인이 성공하고, 토큰이 localStorage에 저장되어야 함", async () => {
    const mockTokenResponse = { memberId: 1, token: "test-token" };
    const testServer = createTestServer([createLoginSuccessHandler(mockTokenResponse)]);
    // 테스트용 서버(MSW) 시작
    testServer.listen();
    
    renderWithProviders(<LoginForm />);

    // 사용자 입력 시뮬레이션
    await userEvent.type(screen.getByLabelText("이메일"), "test@example.com");
    await userEvent.click(screen.getByRole("button", { name: "로그인" }));

    // 결과 확인: 로컬스토리지에 토큰 저장됐는지 검증
    await waitFor(() => {
      expect(authApi.getToken()).toBe("test-token");
    });

    // 테스트용 MSW 서버 종료
    testServer.close();
  });
});

 

위 테스트는 실제로 백엔드 서버를 띄운 적은 없지만, MSW를 통해 마치 진짜 서버와 통신하듯 로그인 과정을 재현했습니다.

Testing Library를 사용해 사용자의 입력 이벤트를 흉내내고, MSW가 준비한 가짜 응답(test-token)을 받아 로컬스토리지가 업데이트되었는지를 검증함으로써, 전체 로그인 흐름이 문서 요구사항대로 이루어지는지를 자동 테스트한 것입니다. MSW 덕분에 테스트 환경의 리액트 컴포넌트는 실제 API와 대화한다고 믿고 있지만, 뒤에서는 우리의 가짜 서버가 응답을 주고 있기에 네트워크 의존성 없이도 신뢰성 있는 통합 테스트가 가능합니다.

 

중요한 점은, 이러한 테스트가 단순히 기능이 동작하는지를 넘어 문서에 정의된 시나리오가 제대로 구현되었는지”를 검증한다는 것입니다. 즉, 문서 → 코드 → 테스트의 일관성이 확보되는 것이죠.

 

MSW를 통한 테스트는 실패할 수도 있습니다(예를 들어, 문서에 따른 시나리오대로 동작하지 않으면 테스트가 실패). 그 실패는 개발팀에게 곧바로 피드백으로 돌아옵니다. “무엇이 틀렸는가? 문서의 시나리오가 잘못됐는가, 아니면 구현된 코드에 버그가 있는가?”와 같은 질문을 던지게 함으로써, AI는 문서와 코드의 불일치를 조기에 발견하고 수정할 수 있습니다.

이처럼 MSW + 테스트 코드 조합은 문서로부터 출발한 기대 동작을 실제 코드에서 자동으로 검증해주는 피드백 루프를 실현합니다.

 

결론 – 문서와 코드, 테스트의 삼각 루프

MCP와 같은 기술을 통해 문서와 디자인, 데이터가 연결되고, MSW와 테스트 코드를 통해 문서의 내용이 자동으로 검증될 수 있습니다. 이러한 환경에서는 문서가 곧 실행 가능한 스펙이 되고, 코드와 테스트는 그 스펙을 구현하고 확인하는 역할을 합니다. 문서가 바뀌면 코드가 바뀌고, 코드가 바뀌면 테스트가 이를 잡아내고, 테스트 결과는 다시 문서에 반영되는 선순환이 자리잡게 됩니다.

결국 “문서가 살아 있으면 팀도 살아 있다.” 문서가 최신 상태로 실행되고 있다면, 그 팀은 공유된 이해를 바탕으로 빠르게 움직일 수 있습니다. 그리고 “테스트는 문서의 진실을 증명하는 거울”이 되어, 우리의 문서(요구사항)가 정말 현실에서 지켜지고 있는지를 항상 비춰줍니다. 문서-코드-테스트가 삼위일체가 된 개발 문화야말로 빠른 변화 속에서도 품질과 이해도를 높이는 길일 것입니다

 

 

P.S)
1~2주동안 써봤는데, 문서 기록, jira 연동, 개발이 빠르게 연동되어 개발 외 일의 생산성이 매우 높아져
아주 만족도가 높습니다..! 

반응형

+ Recent posts