Big Project · AI's EYE 03
R&R: 영역 이름표에서 '작업 계약'으로
역할을 개발·데이터·프런트처럼 나눴다면 업무 분배는 끝난 것처럼 보인다. 왜 담당자가 있는데도 완료 여부를 다시 확인해야 했는지 의문이다.
근거 · 프로젝트 문서 · 코드 · 테스트
1장: R&R이 ‘이름표’일 때의 불편함
솔라는 방금 회의를 마치고 온 사람처럼 잔뜩 찡그린 얼굴로 거실 소파에 앉았다. 손에 든 태블릿 화면에는 여러 색깔의 카드들이 ‘To Do’, ‘In Progress’, ‘Done’ 같은 칸에 흩어져 있었다. 팀의 칸반 보드였다.
“언니, 나 진짜 답답해 죽겠어.”
노트북으로 무언가 작업하던 루나가 고개를 들었다. 솔라의 시선은 화면 한쪽에 고정되어 있었다. 각 팀원의 이름과 사진 옆에 붙은 ‘프런트엔드’, ‘백엔드’, ‘데이터 분석’ 같은 역할 이름표였다.
“왜? 지난주에 역할 분담(R&R) 새로 다 정했다고 하지 않았어? 이제 각자 뭘 할지 명확해져서 속 시원하다며.”
“그러니까 말이야. 명확해진 줄 알았지!”
솔라는 태블릿을 루나 쪽으로 휙 돌렸다.
“봐봐. ‘로그인 기능 개선’ 이슈가 몇 주째 ‘In Progress’에 머물러 있어. 담당자는 ‘백엔드 개발자’로 딱 정해져 있고. 그런데 아무 진척이 없는 거야. 물어보면 ‘하는 중’이래. 프런트엔드 담당자는 ‘백엔드 API가 안 나와서 시작을 못 해요’라고 하고. 아니, R&R을 정했으면 각자 알아서 맡은 분야의 일을 딱딱 끝내야 하는 거 아니야? 백엔드 개발자는 개발을 하고, 프런트엔드 개발자는 화면을 만들고. 뭐가 이렇게 어려운 거지?”
솔라의 목소리에는 ‘당연히 그래야 하는 것 아니냐’는 억울함이 묻어났다. 역할과 책임을 나눈다는 것은 각자 자기 영역의 전문가로서 일을 처리한다는 뜻이라고, 솔라는 굳게 믿고 있었다. 하지만 현실은 달랐다. 이름표는 선명하게 붙어있는데, 일은 앞으로 나아가지 않았다.
루나는 잠시 솔라가 내민 태블릿을 들여다보더니, 옆에 있던 작은 화이트보드를 가져왔다. 보드마카를 들어 간결하게 세 개의 영역을 그렸다.
[ 팀 A ]
- 솔라: 기획
- 팀원 B: 개발
- 팀원 C: 디자인
“자, 우리 팀이라고 해보자. 그리고 다음 주 목표는 ‘사용자 프로필 페이지 만들기’야. 팀원 B의 역할은 ‘개발’이지.”
루나는 솔라에게 보드마카를 건넸다.
“솔라 네가 기획자야. 여기 이 ‘개발’이라는 이름표 하나만 보고, 팀원 B가 다음 주 월요일 아침 9시에 컴퓨터를 켜서 가장 먼저 해야 할 구체적인 작업, 딱 한 가지만 적어볼래?”
솔라는 자신만만하게 마카를 받아 들었다. ‘그거야 쉽지.’ 그녀는 ‘팀원 B’의 이름 밑에 망설임 없이 적었다.
프로필 페이지 개발 시작
루나는 말없이 솔라가 쓴 글씨를 가리켰다.
“‘개발 시작’이라. 좋아. 그럼 팀원 B는 데이터베이스 테이블 설계부터 해야 할까? 아니면 API 엔드포인트부터 만들어야 할까? 그것도 아니면 일단 화면 레이아웃부터 코드로 짜기 시작해야 할까? 팀원 C의 디자인 시안은 나왔나? 기획서에 필요한 모든 필드 정의는 확정된 거고?”
연이어 쏟아지는 질문에 솔라의 손이 멈칫했다. ‘개발 시작’이라는 네 글자가 갑자기 흐릿하고 거대한 안개처럼 보였다. ‘개발’이라는 역할 이름표만으로는 월요일 아침의 첫 작업을 도저히 정할 수 없었다. 팀원 B가 어떤 입력을 받아야 일을 시작할 수 있는지, 어떤 순서로 진행해야 하는지, 아무것도 알 수 없었다.
솔라는 자신이 적은 글씨를 지웠다. 다시 적으려 했지만, 무엇을 적어야 할지 막막했다. ‘API 설계’? ‘데이터 모델링’? 모두 ‘개발’의 일부였지만, 무엇이 먼저인지, 무엇이 필요한지 이 이름표만으로는 판단할 근거가 없었다.
“…못 적겠어.”
솔라는 마침내 항복하듯 말했다.
“그냥 ‘개발’이라고만 해서는, 그 사람이 당장 뭘 해야 할지, 우리가 뭘 기대해야 할지 전혀 알 수가 없구나. 시작점이 어딘지, 끝점이 어딘지도 모르겠어.”
바로 조금 전까지 팀원들을 답답해하던 자신의 모습이 떠올랐다. ‘백엔드 개발자’라는 이름표를 붙여주고 ‘왜 알아서 못 해?’라고 생각했던 것이 얼마나 막연한 기대였는지 깨달았다. 역할 이름표는 담당 영역을 알려줄 뿐, 작업의 시작과 끝, 필요한 조건까지 알려주지는 않았다. 그것은 마치 지도에 ‘서울’이라고 표시만 해두고, 그 안에서 ‘광화문’을 찾아오라고 하는 것과 같았다.
솔라는 다시 팀의 칸반 보드를 보았다. 이제 ‘백엔드 개발자’라는 이름표는 더 이상 명쾌한 책임의 상징으로 보이지 않았다. 오히려 ‘그래서 구체적으로 무엇을?’이라는 질문을 던지는, 거대한 모호함의 표식처럼 느껴졌다.
“알겠어, 언니. 역할 이름표만 붙여놓는 건 아무 의미가 없구나. 오히려 서로 다른 기대를 하게 만들어서 일을 더 꼬이게 만드는 거였어.”
문제가 무엇인지는 알았다. 하지만 해결책은 떠오르지 않았다. 모호해서 문제라는 건 알겠는데, 그럼 이 막연함을 어떻게 해야 한단 말인가.
“그럼 저 ‘로그인 기능 개선’처럼 크고 모호한 작업 덩어리는 어떻게 해야 해? 그냥 두면 안 된다는 건 알겠는데…”
2장: 큰 그림을 작은 ‘Issue’로 나누는 기술
솔라의 질문이 거실 공기 중에 맴돌았다. 루나는 대답 대신, 솔라가 보고 있던 태블릿을 가져와 그 옆에 있던 자신의 업무용 노트북을 열었다. 텅 빈 문서 편집기 화면이 나타났다.
루나는 키보드를 두드려 문서의 제목을 입력했다. [작업 명세서] 로그인 기능 개선. 그리고 그 아래에 큰 사각형 하나를 그렸다. 마치 지난 장에서 솔라가 좌절하며 바라보던, 칸반 보드의 거대한 카드처럼 보였다. 솔라의 질문, ‘크고 모호한 작업 덩어리는 어떻게 해야 해?’가 눈앞의 도형으로 구체화된 순간이었다.
“이 ‘로그인 기능 개선’이라는 상자를 솔라 네가 직접 더 작은 상자들로 나눠볼래? 딱 봐도 너무 크잖아.”
“나누는 거야 좋지. 그런데 어떻게?”
솔라는 막막했지만, 일단 노트북을 자기 쪽으로 당겨왔다. ‘로그인 기능 개선’이라는 목표를 달성하기 위해 필요한 일들을 머릿속으로 떠올려 보았다. 개발자가 할 일, 디자이너가 할 일, 기획자인 자신이 할 일… 자연스럽게 역할 이름표를 따라 생각이 흘러갔다.
솔라는 잠시 고민하다가 키보드를 두드리기 시작했다.
백엔드 작업: 로그인 로직 수정프런트엔드 작업: 로그인 화면 UI 변경기획/디자인: 변경된 정책 및 화면 기획
“이 정도? 각자 맡은 부분을 나눠서 하면 되지 않을까?”
솔라는 나름대로 ‘분할’을 했다는 생각에 조금 뿌듯한 얼굴로 루나를 쳐다봤다. 하지만 루나는 고개를 저었다.
“이건 그냥 큰 이름표를 작은 이름표로 바꾼 것뿐이야. ‘백엔드 작업’은 여전히 ‘그래서 구체적으로 무엇을?’이라는 질문에 답하지 못해. 이건 작업을 나눈 게 아니라, 책임을 다시 한번 모호하게 나눴을 뿐이지.”
다시 원점이었다. ‘모호하다’는 지적에 솔라는 입술을 깨물었다. 그냥 더 열심히 생각하면 될 문제가 아닌 것 같았다. 큰 문제를 단번에 해결하려는 생각, 혹은 그저 더 열심히 하자는 다짐만으로는 이 거대한 상자를 쪼갤 수 없었다.
루나는 다시 노트북을 가져가 솔라가 작성한 목록을 지웠다. 대신 다른 질문을 던졌다.
“사용자가 ‘로그인 기능이 개선됐다’고 느끼려면, 우리가 무엇을 바꿔야 할까? 우리가 만든 결과물 중에서 사용자가 직접 만지고 경험할 수 있는 가장 작은 변화는 뭘까?”
‘사용자 경험’이라는 새로운 관점이었다. 솔라는 지금까지 개발자, 디자이너의 입장에서만 생각했다는 것을 깨달았다. 사용자는 ‘백엔드 로직’이나 ‘프런트엔드 UI’를 경험하지 않는다. 그들은 ‘소셜 로그인 버튼’을 누르거나 ‘비밀번호 찾기’를 통해 문제를 해결할 뿐이다.
관점을 바꾸자 안갯속 같던 ‘로그인 기능 개선’의 실체가 조금씩 보이기 시작했다. 솔라는 다시 노트북 앞에 앉았다. 이번에는 손가락 움직임이 훨씬 구체적이었다.
- Issue #1:
로그인 페이지에 '비밀번호 찾기' 링크 추가- 설명: 현재 로그인 페이지에는 비밀번호를 잃어버렸을 때 대처할 방법이 없음. 링크 텍스트와 아이콘을 추가한다.
- Issue #2:
이메일로 임시 비밀번호를 발송하는 기능 구현- 설명: ‘비밀번호 찾기’를 누른 사용자에게 임시 비밀번호를 생성하고 이메일로 보내준다.
- Issue #3:
'구글 계정으로 로그인' 기능 추가- 설명: 사용자가 구글 계정을 이용해 간편하게 로그인할 수 있도록 OAuth2.0 연동 기능을 추가한다.
- Issue #4:
로그인 오류 메시지를 구체적으로 표시- 설명: 현재 ‘로그인 실패’라고만 뜨는 메시지를 ‘아이디가 존재하지 않습니다’, ‘비밀번호가 틀렸습니다’ 등으로 구분해서 보여준다.
솔라는 자신이 작성한 목록을 보며 놀라워했다. ‘로그인 기능 개선’이라는 하나의 거대한 덩어리가, 이제는 누구라도 보고 “아, 이 일을 하면 되는구나”라고 이해할 수 있는 네 개의 작은 작업으로 나뉘었다. 각 Issue는 그 자체로 독립적으로 시작하고 끝낼 수 있는 구체적인 행동 계획이었다.
“와… 이렇게 하니까 완전 다르다.”
솔라는 감탄하며 말했다.
“‘백엔드 작업’이라고 했을 땐 어디서부터 손대야 할지 막막했는데, ‘이메일로 임시 비밀번호 발송 기능 구현’이라고 하니까 뭘 해야 할지 명확하게 보여. 심지어 이건 프런트엔드 작업이 없어도 먼저 개발하고 테스트할 수 있겠네.”
이제 ‘작업 분할’이라는 도구의 힘을 어렴풋이 알 것 같았다. 큰 그림을 작은 조각으로 나누는 것. 그것은 단순히 일을 나누는 게 아니라, 모호함을 제거하고 각 조각에 실행 가능한 의미를 부여하는 과정이었다.
“그래. 이제 이 Issue들을 팀원들에게 나눠주면 각자 알아서 잘할 수 있겠지?”
자신감에 찬 솔라의 말에 루나는 미소만 지을 뿐, 선뜻 동의하지 않았다. 루나는 솔라가 작성한 목록에서 두 번째 항목을 손가락으로 가리켰다.
Issue #2: 이메일로 임시 비밀번호를 발송하는 기능 구현
“좋아. 그럼 이 Issue를 맡은 개발자는 월요일 아침에 제일 먼저 뭘 해야 할까? 그리고 우리는 그 일이 ‘완성’되었다는 걸 어떻게 알 수 있을까?”
순간 솔라의 머릿속이 다시 하얘졌다. 분명 아까보다는 훨씬 명확해졌다고 생각했는데. 이메일을 보내려면… 이메일 디자인 시안이 있어야 하나? 어떤 서버를 통해 보내지? 성공했다는 건 이메일이 내 편지함에 도착하면 되는 건가, 아니면 서버에 기록이 남아야 하는 건가?
작은 Issue로 나눴음에도 불구하고, 여전히 그 안에는 보이지 않는 모호함이 숨어 있었다.
3장: ‘무엇을 받아, 무엇을 줄까?’ 입력과 출력 정의하기
루나의 마지막 질문은 솔라의 자신감에 찬물을 끼얹었다. ‘작업을 잘게 쪼갰으니 이제 됐다’고 생각했는데, 그 작은 조각조차도 여전히 모호함의 씨앗을 품고 있었다. 솔라는 밤새 뒤척이다 다음 날 아침, 루나가 다시 노트북을 열기 전에 먼저 태블릿을 들고 나타났다. 어제 작성하던 [작업 명세서] 로그인 기능 개선 문서가 화면에 떠 있었다.
문서는 조금 바뀌어 있었다. 솔라는 어젯밤 루나의 질문이 맴돌았던 Issue #2 아래에 무언가를 덧붙여 놓았다.
Issue #2: 이메일로 임시 비밀번호를 발송하는 기능 구현
- 설명: ‘비밀번호 찾기’를 누른 사용자에게 임시 비밀번호를 생성하고 이메일로 보내준다.
- 담당자: 백엔드 개발자
- 요청사항: 이메일 발송 API 연동해서 기능 구현할 것.
“언니, 봐봐. 이렇게 하면 되지 않을까? 개발자에게 뭘 해야 할지 좀 더 구체적으로 적어줬어. ‘API 연동해서 구현하라’고.”
솔라는 자신이 문제를 해결했다고 믿는 듯한 표정이었다. ‘알아서 하라’는 막연한 지시보다는 분명 나아 보였다. 하지만 루나는 솔라가 추가한 줄을 잠시 보더니, 키보드를 가져가 문서의 구조를 바꾸기 시작했다. Issue #2의 설명 아래에 있던 ‘담당자’, ‘요청사항’ 같은 항목들을 지우고, 대신 그 자리에 세 개의 빈칸으로 이루어진 표를 만들었다.
| 입력 (Input) | 작업 (Process) | 출력 (Output) |
|---|---|---|
Issue #2: 이메일 임시 비밀번호 발송 |
“솔라야, 모든 일은 작은 공장 같은 거야.”
루나는 표의 첫 번째 칸 ‘입력’을 손가락으로 톡 쳤다.
“공장에 원자재가 들어가야 제품이 나오잖아. 작업도 똑같아. 이 개발자가 ‘이메일 발송 기능 구현’이라는 작업을 시작하려면, 어떤 원자재가 필요할까? ‘API 연동해서 구현하라’는 건, ‘공장 알아서 돌려봐’랑 크게 다르지 않아.”
‘알아서’라는 단어에 솔라의 미간이 살짝 찌푸려졌다. 분명 더 구체적으로 만들었다고 생각했는데, 다시 원점으로 돌아온 기분이었다. 작업의 시작은 그저 담당자에게 일을 넘기는 것이고, 결과물만 잘 나오면 된다고 생각했던 기존의 관점이 흔들렸다.
“원자재… 라고?”
“응. 이 개발자가 코딩을 시작하기 위해 손에 쥐고 있어야 하는 모든 것. 기획서, 디자인 시안, 정책 문서, 필요한 계정 정보 같은 것들 말이야. 그게 ‘입력’이야.”
루나는 표의 마지막 칸 ‘출력’을 가리켰다.
“그리고 이 작업이 끝났을 때, 우리가 손에 쥐게 되는 결과물. 그게 ‘출력’이지. 단순히 ‘기능 구현 완료’라는 상태가 아니라, 구체적인 산출물.”
루나는 스크롤을 올려 어제 솔라가 만들었던 다른 이슈를 화면 중앙에 놓았다.
Issue #1: 로그인 페이지에 '비밀번호 찾기' 링크 추가
“자, 연습 삼아 이걸로 해보자. 이 작업의 입력과 출력은 뭘까?”
솔라는 잠시 고민했다. ‘비밀번호 찾기’ 링크를 만드는 개발자의 입장이 되어보았다. 빈 화면에 코드를 짤 수는 없다. 뭐가 필요하지?
“음… 입력은… 일단 어떻게 생겼는지 알아야 하니까 ‘디자인 시안’?”
“좋아. 또?”
“어디에 넣을지, 누르면 어디로 가야 하는지도 알아야 하니까… ‘기획서’?”
“정확히는 ‘기획서의 어느 부분’일까? ‘디자인 시안의 어느 화면’일까?”
루나의 집요한 질문에 솔라는 한 단계 더 깊이 생각해야 했다. 막연한 문서 제목이 아니라, 작업에 필요한 정확한 정보의 위치를 떠올렸다.
“입력은… 로그인 페이지 관련 기획 명세랑, Figma에 있는 로그인 UI 디자인 시안 링크!”
생각이 명확해지자 목소리에 힘이 붙었다. 솔라는 신나서 ‘출력’ 칸으로 넘어갔다.
“출력은… ‘비밀번호 찾기’ 링크가 생긴 로그인 화면!”
“그 화면을 우리가 어떻게 확인할 수 있을까? 개발자 컴퓨터에만 있으면 소용없잖아.”
“아! 개발 서버에 배포된 로그인 페이지에서, 우리가 직접 눈으로 보고 클릭해볼 수 있어야 해. 그리고 그 페이지를 만드는 React 컴포넌트 코드도 결과물이겠네.”
솔라는 자신이 말한 내용을 표에 채워 넣었다.
| 입력 (Input) | 작업 (Process) | 출력 (Output) |
|---|---|---|
| - 로그인 페이지 기획 명세서 (v1.2) - Figma 디자인 시안 링크 | Issue #1: '비밀번호 찾기' 링크 추가 | - 개발 서버에서 확인 가능한 로그인 페이지 - PasswordResetLink React 컴포넌트 코드 |
텅 비어있던 표가 채워지자, 막연했던 작업이 하나의 선명한 ‘흐름’으로 보였다. 특정 문서를 받아, 특정 코드를 만들어내고, 특정 환경에서 확인할 수 있게 만드는 과정. 이 표만 있다면 누가 이 일을 하든 길을 잃을 염려는 없어 보였다. 이제야 비로소 지난 장에서 느꼈던 ‘그래서 구체적으로 무엇을?’이라는 질문에 대한 답을 찾은 것 같았다.
솔라는 다시 스크롤을 내려 자신이 아침에 자신만만하게 수정했던 Issue #2를 보았다. 이제 ‘API 연동해서 기능 구현할 것’이라는 문장은 너무나 공허하게 느껴졌다. 개발자가 이메일을 보내려면 어떤 내용의 이메일을 보내야 하는지(입력), 어떤 발송 서버 정보를 써야 하는지(입력) 알려주지 않았다. 그리고 일이 끝났을 때, 임시 비밀번호가 담긴 이메일 본문(출력)을 확인해야 하는지, 아니면 서버에 성공 기록이 남는 것(출력)으로 충분한지 정해주지 않았다.
“알겠다… 내가 뭘 잘못했는지 알겠어.”
솔라가 말했다.
“나는 계속 사람을 보고 ‘이 사람이 알아서 해주겠지’라고 생각했어. 하지만 문제는 사람이 아니라, 이 ‘입력’과 ‘출력’을 명확하게 알려주지 않은 나한테 있었던 거야. 지시가 모호하니까 결과가 미완료 상태로 계속 떠돌아다녔던 거고.”
솔라는 이제 R&R이 단순한 역할 이름표가 아니라, 작업과 작업 사이를 잇는 약속이라는 것을 깨달았다. ‘무엇을 줄 테니, 무엇을 달라’는 명확한 계약.
“좋아! 이제 모든 이슈에 이렇게 입력과 출력을 꼼꼼하게 적어주면 되겠네. 그럼 오해할 일도 없고, 일이 중간에 멈출 일도 없겠지!”
솔라가 만족스러운 듯 말하며 방금 채운 표의 ‘출력’ 부분을 가리켰다. 루나는 그곳에 적힌 개발 서버에서 확인 가능한 로그인 페이지라는 글자를 조용히 응시했다.
“개발자가 작업을 마치고 ‘개발 서버에 올렸어요. 이제 확인 가능합니다.’라고 우리에게 말했어. 그럼 이 일은 ‘완료’된 걸까?”
“응! 출력이 나왔으니까!”
“만약 우리가 링크를 클릭했는데 아무 반응이 없으면? 혹은 PC에선 잘 보이는데, 모바일 화면에선 글자가 깨져 보인다면? 그것도 ‘완료’된 걸까?”
솔라의 얼굴에 떠올랐던 확신이 다시 한번 흔들렸다. 출력이 나왔다고 해서, 일이 끝난 것은 아닐지도 모른다는 새로운 불안감이 싹텄다.
4장: ‘완료’란 무엇인가? 객관적인 기준 세우기
루나의 마지막 질문이 남긴 불안감은 쉽게 가시지 않았다. 솔라는 다음 날에도 어제의 그 표를 화면에 띄워 놓고 있었다. ‘입력’, ‘작업’, ‘출력’으로 이어진 명쾌한 흐름이라고 생각했는데, 마지막 ‘출력’ 단계에서 거대한 함정을 만난 기분이었다.
| 입력 (Input) | 작업 (Process) | 출력 (Output) |
|---|---|---|
| - 로그인 페이지 기획 명세서 (v1.2) - Figma 디자인 시안 링크 | Issue #1: '비밀번호 찾기' 링크 추가 | - 개발 서버에서 확인 가능한 로그인 페이지 - PasswordResetLink React 컴포넌트 코드 |
‘출력이 나왔다고 해서, 일이 끝난 것은 아닐지도 모른다.’
이 생각의 고리를 끊기 위해 솔라는 일부러 더 밝게 말했다.
“언니, 그래도 출력이 나온 게 어디야! 개발 서버에 올라왔다는 건 어쨌든 결과물이 있다는 뜻이잖아. 모바일에서 깨져 보이면 ‘수정 요청’을 하면 되는 거고. 그건 또 다른 일이지, 원래 일이 안 끝났다고 할 순 없지 않아?”
그것은 솔라가 오랫동안 일하며 익숙해진 방식이었다. ‘다 했다’는 보고를 받으면, 확인해보고, 문제가 보이면 다시 요청한다. 담당자가 ‘다 했다’고 말하는 순간, 혹은 상사가 ‘이 정도면 됐다’고 판단하는 순간이 ‘완료’라고 믿어왔다.
루나는 솔라의 말에 대답하는 대신, 조용히 키보드를 가져갔다. 그리고는 표의 맨 오른쪽에 새로운 칸을 하나 추가했다. 그 칸의 제목은 간결했다.
완료 기준 (Acceptance Criteria)
| 입력 (Input) | 작업 (Process) | 출력 (Output) | 완료 기준 (Acceptance Criteria) |
|---|---|---|---|
| - 로그인 페이지 기획 명세서 (v1.2) - Figma 디자인 시안 링크 | Issue #1: '비밀번호 찾기' 링크 추가 | - 개발 서버에서 확인 가능한 로그인 페이지 - PasswordResetLink React 컴포넌트 코드 |
텅 빈 네 번째 칸이 솔라의 눈에 들어왔다. 루나는 그 칸을 턱짓으로 가리켰다.
“개발자가 ‘다 했다’고 말했을 때, 솔라 네가 ‘수정 요청’을 해야 하는 상황. 그건 이 칸을 미리 채우지 않았기 때문이야. ‘수정 요청’은 새로운 일이 아니야. 애초에 끝나지 않은 일을 끝내달라는 의미지. 자, 저 빈칸을 채워봐. 우리가 이 일이 ‘완료’되었다고 모두가 동의할 수 있는 객관적인 조건은 뭘까?”
객관적인 조건. 그 말이 솔라의 머리를 쳤다. 지금까지 ‘완료’는 담당자의 선언이나 확인자의 주관적인 판단에 의존하는 것이라 생각했다. 하지만 루나는 그것을 하나의 ‘조건’으로, 마치 수학 공식처럼 정의하라고 요구하고 있었다.
솔라는 마지못해 키보드에 손을 올렸다. 그리고 ‘완료 기준’ 칸에 첫 번째 항목을 입력했다.
링크가 잘 동작해야 함.
쓰고 나서 보니 너무 막연했다. 루나의 날카로운 질문이 바로 예상됐다. ‘잘’이 뭔데? 솔라는 얼른 지우고 다시 고민했다. ‘어떻게 하면 논쟁의 여지가 없을까?’
‘로그인 UI 개발’이라는 작업을 맡은 개발자와, 그것을 기다리는 기획자인 내가 서로 다른 말을 하지 않으려면? 답은 하나였다. 누구든 똑같이 확인할 수 있는 명확한 체크리스트를 만드는 것.
솔라의 손가락이 다시 움직이기 시작했다. 이번에는 망설임이 없었다.
- 완료 기준 (Acceptance Criteria)
데스크톱(Chrome, Safari), 모바일(Chrome iOS) 환경에서 디자인 시안과 동일한 위치와 모양으로 보여야 한다.링크에 마우스를 올리면(hover) 밑줄이 생기고, 커서 모양이 포인터로 바뀌어야 한다.링크를 클릭하면 '/password/reset' 주소의 페이지로 화면 전환이 일어나야 한다.페이지 전환에 걸리는 시간은 2초를 넘지 않아야 한다.
하나씩 적어 내려갈수록 머릿속이 맑아지는 기분이었다. 이것은 더 이상 감상의 영역이 아니었다. 누가 봐도 명백하게 ‘예/아니오’로 판정할 수 있는 검증 항목들의 목록이었다. 이 기준을 통과하지 못했다면, 개발자가 아무리 ‘다 했다’고 주장해도 일이 끝나지 않았음이 명백했다. 반대로, 이 기준들을 모두 통과했다면 기획자인 솔라가 개인적인 취향을 이유로 ‘마음에 안 든다’고 말할 수 없었다.
“알겠다…”
솔라는 자신이 작성한 목록을 보며 나지막이 중얼거렸다.
“출력은 그냥 ‘결과물’이고, 이 완료 기준은 그 결과물이 ‘쓸모 있는 상태’라는 걸 보증하는 거구나. 사람을 탓할 필요가 없었어. 애초에 지시가 다르게 이해될 수밖에 없었던 건, 우리가 같은 결승선을 보고 달리지 않았기 때문이야.”
솔라는 지난 프로젝트에서 겪었던 수많은 갈등을 떠올렸다. 분명 ‘완료’되었다고 해서 다음 작업을 시작했는데, 알고 보니 절반만 동작하는 기능이었던 적이 몇 번이었던가. ‘다 됐다’는 말과 ‘진짜 쓸 수 있다’는 상태 사이의 간극. 그 간극의 이름이 바로 ‘모호한 완료 기준’이었다.
이제 솔라는 ‘완료 조건 정의’라는 새로운 도구를 손에 넣은 것 같았다. 이것은 단순히 일을 더 복잡하게 만드는 서류 작업이 아니었다. 오히려 불필요한 논쟁과 재작업을 막아주는 가장 강력한 안전장치였다.
“좋아. ‘입력’으로 뭘 받을지 정하고, ‘작업’으로 뭘 할지 정의하고, ‘출력’으로 뭘 내놓을지 명시하고, 마지막으로 ‘완료 기준’으로 성공을 판정한다. 이 네 가지가 한 세트였어!”
솔라의 목소리에는 다시금 확신이 차올랐다. 하나의 작업을 오해 없이 시작하고, 논쟁 없이 끝내는 완벽한 흐름을 마침내 완성했다는 생각에 가슴이 뛰었다.
이제 이 강력한 네 단계의 틀만 있으면 어떤 문제든 해결할 수 있을 것 같았다. 하지만 이 완벽해 보이는 사각형의 틀들을 모아 팀 전체의 R&R을 다시 짤 수 있을까? 개별 작업의 명료함이 팀 전체의 명료함으로 이어질 수 있을까? 새로운 질문이 고개를 들었다.
5장: R&R, 이제 ‘작업 계약’으로 다시 쓰다
솔라는 거실 테이블 위에 자신이 밤새 정리한 문서들을 펼쳐 놓았다. ‘로그인 기능 개선’이라는 큰 덩어리를 잘게 나눈 Issue들이었다. 그리고 각 Issue마다 지난 며칠간 루나와 함께 만들었던 네 칸짜리 표가 꼼꼼하게 채워져 있었다. ‘입력’, ‘작업’, ‘출력’, 그리고 ‘완료 기준’까지. 한눈에 봐도 완벽해 보이는 작업 명세서의 집합이었다.
하지만 이 완벽함은 솔라에게 확신 대신 미묘한 불안감을 안겨주었다. 그녀는 태블릿으로 이 문서들을 한데 모아 스크롤하며 루나에게 보여주었다.
“언니, 봐봐. 우리가 이야기한 대로 ‘로그인 기능 개선’에 필요한 모든 작업들을 이렇게 정리했어. 입력, 출력, 완료 기준까지 전부 다. 이제 이대로만 하면 절대 실패할 일은 없겠지.”
말은 그렇게 하면서도 솔라의 목소리 끝은 흐릿했다.
“그런데… 솔직히 좀 걱정돼. 팀원들에게 이걸 다 보여주면 ‘뭐야, 왜 이렇게까지 상세하게 해? 그냥 믿고 맡기면 되지, 일이 더 복잡해지는 거 아니야?’라고 생각하지 않을까? 역할 분담하자고 모였는데, 무슨 서류 작업만 산더미처럼 늘어난 기분이 들 것 같아.”
개별 작업의 명료함은 확보했지만, 이것들이 모이니 거대한 관료주의의 산처럼 느껴졌다. 하나의 작업을 시작하기 위해 읽어야 할 문서가 너무 많아 보였다. 솔라의 질문은 “이 모든 요소를 어떻게 팀 전체의 R&R로 확장하지?”라는 막막함에서 비롯된 것이었다.
루나는 솔라가 화면에 띄워놓은, 빽빽하게 채워진 표들을 잠시 들여다보았다. 그리고는 솔라가 가장 먼저 완성했던 Issue #1: '비밀번호 찾기' 링크 추가의 표를 손가락으로 가리켰다.
“이 표에 있는 정보는 그대로 두고, 표현 방식만 한번 바꿔보자.”
루나는 새 문서 페이지를 열었다. 그리고 표의 내용을 복사해서 붙여넣는 대신, 다른 형식으로 재구성하기 시작했다. 마치 엔지니어가 기술 명세서를 다시 쓰는 것처럼, 그러나 이번에는 법률가가 계약서를 검토하듯 간결하고 명확한 제목을 붙여가며 내용을 옮겨 적었다.
[R&R 작업 계약서]
1. 작업 (Task): 로그인 페이지에 ‘비밀번호 찾기’ 링크를 추가한다.
2. 담당자 (Assignee): TBD (누구나 이 계약을 이행할 수 있음)
3. 제공될 입력 (Inputs Provided):
- 로그인 페이지 기획 명세서 (v1.2)
- Figma 디자인 시안 링크 (figma.com/…)
4. 결과물 (Deliverables):
- 작업 확인이 가능한 개발 서버 페이지 URL
PasswordResetLinkReact 컴포넌트 코드 Pull Request
5. 완료 조건 (Acceptance Criteria):
- 데스크톱(Chrome, Safari), 모바일(Chrome iOS)에서 디자인 시안과 일치하는가?
- 링크에 마우스 호버 시, 밑줄과 포인터 커서가 정상 동작하는가?
- 링크 클릭 시, ‘/password/reset’ 페이지로 2초 내에 전환되는가?
솔라는 잠시 숨을 죽이고 화면을 보았다. 분명 내용은 솔라가 만든 표에 있던 것과 100% 동일했다. 하지만 느낌은 완전히 달랐다. 복잡한 명세서의 나열이 아니라, 하나의 완결된 ‘계약서’처럼 보였다. 특히 담당자: TBD와 각 완료 기준 앞에 붙은 빈 체크박스 [ ]는 이 문서의 성격을 극적으로 바꾸었다.
“이건… 그냥 지시가 아니네.”
솔라가 말했다.
“누가 이 일을 맡든, 이 계약서만 보면 뭘 받아서, 뭘 만들고, 언제 끝났다고 말할 수 있는지 정확하게 알 수 있겠어. 심지어 이 일을 하던 사람이 중간에 아파서 다른 사람에게 넘겨줘야 해도, 이 계약서 한 장만 전달하면 아무 문제 없이 이어받을 수 있겠구나.”
솔라는 비로소 깨달았다. 이 모든 상세한 내용들은 일을 더 복잡하게 만드는 서류 작업이 아니었다. 오히려 불필요한 의사소통 비용과 재작업, 그리고 ‘사람을 탓하는’ 상황 자체를 원천적으로 차단하는 가장 효과적인 장치였다. 이것은 ‘누가 무엇을 한다’는 영역 이름표가 아니라, ‘어떤 작업을, 어떤 조건으로, 누구나 수행하고 검증할 수 있다’는 투명한 약속이었다.
“맞아. 핵심은 내가 모든 일을 대신 해주거나, 누군가를 감시하려는 게 아니었어.”
솔라는 처음 R&R을 정하던 때를 떠올렸다. ‘백엔드 개발자’라는 이름표를 붙여주고 ‘왜 알아서 못 해?’라고 답답해했던 자신. 그 모든 갈등의 원인은, 애초에 재배정과 완료 기준을 명확하게 합의하지 않았기 때문이라는 사실을 이제는 알 수 있었다.
“R&R은 역할의 이름이 아니라, 작업의 계약이었구나.”
솔라의 목소리에는 더 이상 불안감이 없었다. 그녀는 루나가 만든 템플릿을 복사했다. 그리고 처음 이 모든 여정을 시작하게 했던, 팀 칸반 보드에 몇 주째 멈춰 있던 그 카드를 떠올렸다.
[In Progress] 로그인 기능 개선
솔라는 자신의 태블릿에서 그 낡고 모호한 카드를 지우는 상상을 했다. 대신, 자신이 직접 만든 ‘R&R 작업 계약서’를 첨부한 새로운 카드들을 올리는 모습을 그렸다.
솔라는 더 이상 상상에만 머무르지 않았다. 태블릿의 문서 앱을 열고, 비어있는 페이지에 조금 전 루나가 보여준 것과 같은 제목을 입력했다.
[R&R 작업 계약서]
그리고 첫 번째 항목을 채워 넣기 시작했다. 팀의 진짜 문제를 해결하기 위한, 명확하고 실행 가능한 첫 번째 계약이었다.