이력서의 연차로는 일하는 방식을 알 수 없다. 점수를 매기지 않는 Grift로 실제 OSS 4개를 측정해 보았다
이력서의 연차나 공수(맨먼스)만으로는 그 사람이 어떤 방식으로 일해 왔는지 알 수 없습니다. Cor.이 점수도 순위도 매기지 않는 Grift를 만든 이유와 MBTI와의 차이점, 실제 OSS 4개를 측정하여 보인 것과 보이지 않았던 점을 소개 회사·SES 영업 담당자 및 엔지니어 여러분을 위해 전합니다.
이력서에 ‘Python 5년’이라고 적혀 있어도, 그 5년 동안 어떤 일을 해왔는지는 알 수 없습니다.
연차나 맨먼스(man-month)는 일의 양을 가늠하는 기준은 됩니다. 하지만 동작을 확인하는 테스트를 작성하며 진행하는 사람인지, 문서를 정돈하는 사람인지, 작은 변경을 자주 반영하는 사람인지, 일하는 방식까지는 알려주지 않습니다.
소개 회사나 SES의 영업 담당자가 추천 이유를 근거 있게 말하지 못해 말문이 막히고 맙니다. 그 원인 중 하나가 바로 이 틈새에 있다고 Cor.는 생각합니다.
점수를 매기지 않는 이유
Grift는 이 틈새를 메우기 위해 만든 자체 프로덕트입니다. git(소프트웨어의 변경 사항을 매회 기록하는 체계)에 남은 기록에서 업무 성향과 그 근거가 된 건수를 추출합니다. 점수도 순위도 매기지 않습니다.
대표인 데라다 코스케은 리크루트에서 구인 광고 영업을 하던 시절, 말이 온전히 전해지지 않는 답답함을 겪었습니다. Grift에 대해서는 “이력은 부풀릴 수 있다. 증거는 부풀릴 수 없다.”라고 적고 있습니다.
점수화를 하면 무슨 일이 일어날까요? 서로 다른 종류의 기록을 하나의 숫자로 뭉뚱그리면, 무엇을 세었는지, 무엇을 셀 수 없었는지가 사라집니다. 그리고 점수가 있으면 높은 사람이 더 좋은 사람처럼 보입니다. 줄을 세우면 순위가 됩니다.
Grift를 통해 저희가 하고자 하는 것은 사람을 순위로 줄 세우는 일이 아닙니다. 그 사람의 업무 성향에 맞는 프로젝트와 사람을 연결하는 것입니다. 이를 위해 확인할 수 있는 사실만을 제시합니다. 판단하는 것은 사람입니다.
MBTI와의 차이점
순위를 매기지 않는다는 말을 듣고 MBTI를 떠올리는 분도 계실지 모릅니다.
MBTI는 본인이 질문에 답하여 4가지 선호 지표의 조합으로 16가지 유형을 도출합니다. MBTI 재단(The Myers & Briggs Foundation)은 모든 유형에는 가치가 있으며, 채용 목적으로 만들어진 것이 아니라고 밝히고 있습니다.
Grift는 질문을 하지 않습니다. 유형 이름도 붙이지 않습니다. 성격을 진단하는 도구도 아닙니다. git에 남은 기록을 세어서 성향과 그 근거가 된 건수를 제시합니다.
차이점은 영업 담당자가 겪는 고민에 대입해 보면 쉽게 이해할 수 있습니다.
이력서의 자기 신고 내용을 어디까지 믿어야 할지 알 수 없다. MBTI 결과 역시 이력서와 마찬가지로 본인의 답변에서 나옵니다. Grift의 근거는 기록입니다. 동일한 기록을 전달하면 누가 세더라도 같은 값이 나옵니다.
연차나 맨먼스로는 일하는 방식을 알 수 없다. Grift는 어떤 영역을 다루어 왔는지(테스트, 문서, 본체 프로그램 등), 변경을 어느 정도의 간격으로 내고 있는지, 수정 변경에 테스트가 수반되어 있는지를 건수로 제시합니다.
다만, 기록에 남지 않는 것은 나오지 않습니다. 회의에서의 기여, 코드 리뷰의 품질, 공개되지 않은 업무는 보이지 않습니다. 본인의 동의가 없다면 개인의 경험이나 역할도 제시하지 않습니다.
TEP라는 절차
Grift는 기록에서 사실을 추출하는 절차를 TEP(Technical Evidence Pipeline, 기술 증거 파이프라인)라고 부릅니다. 내용은 4단계로 이루어져 있습니다.
- git 기록을 읽는다. AI의 추측은 사용하지 않습니다
- 정해진 규칙에 따라 센다. 예를 들어, 파일의 위치와 이름으로부터 테스트인지 문서인지를 구분합니다
- 집계된 값에 분모와 함께 집계되지 않은 항목의 이유를 덧붙인다
- 동일한 절차로 누구나 다시 검증하여 셀 수 있도록 한다
4번째의 다시 세는 작업을 Grift에서는 검산이라고 부릅니다. TEP에 대한 자세한 설명은 Grift 사이트의 TEP 페이지에 있습니다.
실제 OSS로 검증하기
정말 이 절차로 업무 성향을 파악할 수 있을까요? 2026년 10월 25일에 Grift CLI(명령어로 구동하는 Grift 도구)의 다음 버전(0.8.0)으로 확인해 보았습니다. 0.8.0은 이날 시점에서는 아직 출시 준비 중인 상태였습니다.
실제 인물을 동의 없이 측정하지 않도록, 소스 코드가 공개되어 있는 소프트웨어(OSS)를 저장소(한 소프트웨어의 기록을 모아두는 곳) 단위로 측정했습니다. 사람별 숫자는 이 글에 단 하나도 싣지 않았습니다.
측정한 대상은 성격이 서로 다른 4가지입니다.
- click: Python에서 명령어로 구동하는 도구를 만들기 위한 라이브러리(다른 프로그램에서 사용하는 부품)
- flask: Python으로 웹 서비스를 만들기 위한 라이브러리
- httpx: Python으로 웹과 통신하기 위한 라이브러리
- commander.js: JavaScript로 명령어로 구동하는 도구를 만들기 위한 라이브러리
확인된 사실
4가지 모두 측정과 검산 모두 2.5초 이내에 완료되었습니다. 검산 결과는 4가지 모두 전 항목에서 일치했습니다.
저장소별 성격 차이도 확인할 수 있었습니다.
click에서는 기록의 마지막 날까지의 180일 동안 187회의 변경이 있었습니다. 변경과 변경 사이의 간격은 중앙값으로 약 2시간입니다. 짧은 간격으로 변경이 지속되고 있습니다.
flask에서는 문서를 수정한 변경이 1,841회 있어, 본체 프로그램을 수정한 변경(1,765회)보다 더 많았습니다.
httpx에서는 테스트 파일을 포함한 변경이 1,335회 중 575회였습니다.
commander.js에서는 본체 JavaScript 파일이 ‘본체 프로그램’으로 집계되지 않고 ‘기타’로 들어갔습니다. 이는 Grift 규칙의 허점입니다. 본체 프로그램으로 집계하는 확장자(파일명 끝부분)에 JavaScript의 .js가 포함되어 있지 않기 때문입니다.
수치의 오독
측정해 보면서 알게 된 점은 숫자만 나열해 두면 순식간에 잘못 읽게 된다는 사실이었습니다. 5가지 예를 들어보겠습니다.
변경 횟수
변경 횟수가 많은 저장소가 좋은 저장소인 것은 아닙니다. flask의 변경은 3,674회, httpx는 1,335회였습니다. 커밋 이력의 기간은 flask가 5,976일, httpx가 2,517일입니다. 횟수는 이력의 기간과 변경 사항을 한데 모아 병합(merge)하는지 여부에 따라 달라집니다.
문서 변경
문서 변경이 많다고 해서 문서 작성에 열성적이라는 의미는 아닙니다. click에서 문서로 집계된 변경의 약 40%는 문서로서 다룬 파일이 변경 이력(Changelog) 파일뿐이었습니다. 변경할 때마다 변경 이력을 작성하는 저장소에서는 문서 작업 횟수가 늘어납니다.
수정 변경
제목이 ‘fix’(수정)로 시작하는 변경에 테스트가 붙어 있지 않다고 해서 테스트를 작성하지 않는다는 뜻은 아닙니다. flask에서 제목이 ‘fix’로 시작하는 변경을 다시 세어보니, 407회 중 198회는 문서나 설정 파일만을 수정한 변경이었습니다. 제목은 ‘fix typo’(오타 수정) 등이었습니다.
적은 변경 수
변경이 적다고 해서 개발이 중단되었다는 의미는 아닙니다. httpx에서는 관측 대상이었던 180일 동안 변경이 11회밖에 없어 간격이 ‘미관측’(측정 불가)으로 나타났습니다. 측정한 것은 9월 2일에 로컬로 가져온 기록이며, 현재 상태를 나타내는 것은 아닙니다.
활동 일수
활동 일수(변경이 있었던 일수)는 변경 단위를 쪼개는 방식에 따라 늘릴 수 있습니다. 검증을 위해 작은 저장소 2개를 만들어 동일한 5줄을 추가했습니다. 한 번에 모아서 추가하면 활동 일수는 2일, 5일에 걸쳐 1줄씩 추가하면 6일이 됩니다(둘 다 최초 1회를 포함합니다). 내용은 동일합니다.
Grift는 이 숫자를 보정하지 않습니다. 대신 숫자 옆에 “매일 1건의 작은 commit을 남기면 늘어나고, 동일한 변경을 하루에 모으면 줄어듭니다.”라고 명시합니다.
보이지 않았던 것
Grift는 측정할 수 없었던 항목을 ‘미관측’으로 표기합니다. 미관측은 ‘측정할 수 없었다’는 뜻이지, ‘실적이 없었다’는 뜻이 아닙니다. 이번 4개 대상에서는 다음 항목들을 확인할 수 없었습니다.
- 리뷰 및 이슈 관리: GitHub 등의 기록을 제공하지 않았으므로 미관측입니다
- 개인의 경험이나 역할: 본인의 동의가 없으므로 미관측입니다
- 자사 변경 여부: 자사 이메일 주소를 정의하지 않았으므로 모두 ‘판정 불가’로 처리되었습니다
잘 풀리지 않았던 점도 적어둡니다. commander.js의 본체 코드가 ‘기타’로 들어간 것은 앞서 언급했듯이 규칙의 허점 때문입니다. 또한 같은 날 작성한 글에서 “테스트 동시 수정율(본체와 동시에 테스트도 함께 수정한 비율) 역시 형식적인 테스트 수정만으로도 올라간다”라고 적었습니다. 0.8.0에서는 이 주의 문구가 아직 숫자 옆에 표시되지 않습니다. 반영된 것은 활동 일수에 대한 한 줄 문구뿐입니다.
0.8.0에서 수정한 사항
0.7.2(현재 공개 버전)에서는 저장소에 기여한 사람들의 목록이 변경 횟수가 많은 순으로 정렬되어 있었습니다. 맨 위에 있는 사람을 ‘가장 큰 기여를 한 사람’으로 오해할 소지가 있습니다. 0.8.0에서는 ID(개인별로 부여된 식별 기호) 순으로 정렬합니다.
4개의 저장소에서 0.7.2와 0.8.0의 목록을 비교했습니다. 이름과 숫자는 보지 않고 정렬 방식만을 확인했습니다. 0.7.2는 4개 모두 맨 위에 있는 사람이 변경 횟수가 가장 많은 사람이었습니다. 0.8.0에서는 그 사람의 행이 click에서는 467행 중 120행, flask에서는 870행 중 280행, httpx에서는 258행 중 232행, commander.js에서는 203행 중 15행에 위치했습니다.
0.8.0의 목록을 변경 횟수가 많은 순으로 다시 정렬하면 검산을 통과하지 못합니다. 그 외의 수치는 0.7.2와 0.8.0에서 동일했습니다.
프로젝트 요구사항과 나란히 놓기
프로젝트와 연결할 때는 프로젝트 측에서 요구하는 조건을 먼저 작성해 둡니다. Grift에서는 이를 선언(declaration)이라고 부릅니다. git에서 확인된 사실(관측)과는 별도의 칸에 나란히 배치하며, 합격/불합격 여부는 판정하지 않습니다.
시험 삼아 가상의 소규모 프로젝트인 ‘Python 라이브러리 유지보수’를 선언해 보았습니다. 180일 동안 12일 이상의 활동이 있을 것, 변경 간격의 중앙값이 7일 이내일 것, 본체 프로그램과 테스트를 다루었을 것, 단위 테스트가 존재할 것, GitHub 등의 기록도 함께 검토할 것, 이라는 선언입니다.
click에 대입하면, 선언의 ‘12일 이상’ 옆에 관측치인 ‘62일’이 나란히 표시됩니다. GitHub 등의 기록은 제공하지 않았으므로 해당 항목은 미관측 상태로 남습니다.
나란히 배치한 후에도 이전 절에서 다룬 오독 가능성은 그대로 남아 있습니다. commander.js에서 ‘본체 프로그램’이 0회인 것은 규칙의 허점 때문이며, httpx의 간격은 기록이 부족하여 미관측으로 나타납니다. 나란히 놓인 수치를 어떻게 해석할지는 사람이 결정합니다.
엔지니어 본인의 기록과 프로젝트를 나란히 비교하는 활용 방식도 있습니다. 이때는 본인의 동의가 있는 기록만을 사용합니다. 실제 개인을 측정하게 되므로 이 글에서는 테스트해보지 않았습니다.
맺음말
git 기록은 이력서의 문구를 검증할 수 있는 좋은 자료가 됩니다. 하지만 기록에 남지 않는 업무도 존재합니다.
Grift가 제시하는 것은 성향과 그 근거가 되는 건수, 그리고 확인할 수 없었던 항목의 이유입니다. 그로부터 무엇을 판단할지는 문서를 읽는 사람이 결정할 몫입니다.
근거 수치
엔지니어분들이 직접 로컬에서 확인해 보실 수 있도록 측정한 조건과 수치를 정리합니다.
- grift 0.8.0(정의 버전
tep-v0.8.0-2026-10-25). 공개 전 소스(개발용 저장소의87076c8)를 로컬에 설치했습니다 - 비교를 위해 공식 공개 버전인 0.7.2도 동일한 4개 대상에 실행했습니다
- Apple M4 Max, macOS 26.7.1, Python 3.12.9, git 2.54.0
- 대상은 2026년 9월 2일에 clone한 후 업데이트하지 않은 로컬의 4개 저장소입니다
측정한 commit(1회분의 변경 기록)의 SHA(commit마다 부여되는 식별자)와 해당 날짜는 다음과 같습니다.
pallets/click 36baa15ff831b939a22bc527cd76ce653ef6f66d 2026-08-26
pallets/flask d318b683471101618febed18996405ad26462110 2026-08-16
encode/httpx b5addb64f0161ff6bfe94c124ef76f6a1fba5254 2026-02-23
tj/commander.js ba6d13ddb4243e5913367734f8c159089ffe7834 2026-05-29
click을 예로 든 명령어입니다.
git clone https://github.com/pallets/click
git -C click checkout 36baa15ff831b939a22bc527cd76ce653ef6f66d
grift repo click --format both --out out/click
grift verify out/click/report.json --repo click
grift repo는 4가지 모두 2.5초 이내에 끝났으며, grift verify는 4가지 모두 VERIFIED였습니다. 새로 clone한 click에서도 실행 시각 외에는 동일한 결과가 나왔습니다. 공식 공개 버전인 0.7.2와 동일한 소스에서도 여기에 수록한 관측치는 같았습니다.
| 저장소 | 사람이 작성한 commit / merge / bot |
|---|---|
| click | 2,000 / 1,131 / 200 |
| flask | 3,674 / 1,691 / 191 |
| httpx | 1,335 / 41 / 147 |
| commander.js | 1,095 / 284 / 138 |
사람이 작성한 commit은 merge(다른 브랜치의 변경을 반영한 기록)를 제외한 건수입니다. bot(자동으로 변경 사항을 반영하는 프로그램)의 변경은 제외했습니다.
작업 영역(surface_profile)은 파일의 위치와 확장자로 구분을 정의하고, 구분별로 commit을 집계합니다. 1건의 commit이 여러 구분에 해당할 수 있으므로, 합계는 분모를 초과합니다.
| 저장소 | 분모 | test / docs / backend / other |
|---|---|---|
| click | 1,999 | 562 / 1,024 / 1,158 / 309 |
| flask | 3,673 | 627 / 1,841 / 1,765 / 575 |
| httpx | 1,333 | 575 / 501 / 874 / 112 |
| commander.js | 1,094 | 286 / 468 / 0 / 530 |
변경 간격(change_rhythm)은 HEAD 날짜를 관측일로 삼고, 그 이전 180일간의 데이터를 집계합니다. 관측일은 위 SHA의 오른쪽에 적힌 날짜입니다.
| 저장소 | commit / 활동 일수 | 간격의 중앙값 / p90 |
|---|---|---|
| click | 187 / 62일 | 0.08일 / 3.36일 |
| flask | 32 / 19일 | 0.80일 / 15.60일 |
| httpx | 11 / 8일 | 미관측 |
| commander.js | 22 / 18일 | 2.88일 / 17.89일 |
httpx가 미관측으로 나타난 이유는 insufficient_population입니다. 관측 기간 내 commit이 11건으로, 비율을 산출하기 위한 최소 기준인 20건에 미치지 못했습니다.
검증 형태(verification_profile)는 test 위치에 해당하는 commit을 집계합니다.
| 저장소 | test를 포함한 commit | fix 제목에 test도 함께 수정한 commit |
|---|---|---|
| click | 562 / 2,000 | 80 / 249 |
| flask | 627 / 3,674 | 58 / 408 |
| httpx | 575 / 1,335 | 46 / 114 |
| commander.js | 286 / 1,095 | 30 / 106 |
test 종류는 click이 unit 555・불명 23, flask가 unit 484・불명 204, httpx가 unit 554・불명 101, commander.js가 불명 286이었습니다.
미관측 항목은 click・flask・commander.js가 23개, httpx가 27개였습니다. 주요 이유는 다음과 같습니다.
forge_export_not_provided,tracker_export_not_provided: 리뷰, 이슈 관리, 이벤트consenting_actor_required: 경험, 역할, 라이브러리 맥락no_upstream_lineage,parent_repo_not_provided,template_not_provided: upstream과의 관계, 템플릿 상속no_tenant_commits: 자사 commit의 80%가 포함되는 기간survival_scan_disabled: 정착률outcome_declaration_not_provided: 작업 후 발생한 사항에 대한 선언deferred_to_v0.6: 라인 단위의 재작업(0.8.0에서도 0.6 시절의 명칭 그대로 유지되었습니다)
출처(origin)는 4가지 모두 bot을 제외한 전 commit이 unresolved였습니다. 자사 이메일 주소를 정의한 identity.toml도, fork의 부모 저장소도 제공하지 않았기 때문입니다.
click에서 문서로 집계된 commit 내역과 flask의 fix commit 내역은 Grift의 출력 결과가 아닙니다. 동일한 규칙을 git log에 적용하여 로컬에서 다시 집계한 대략적인 수치입니다. click은 1,025건 중 414건에서 문서로서 수정한 파일이 CHANGES.rst뿐이었습니다. flask는 fix 제목의 commit 407건 중 198건이 문서 또는 설정 파일만을 변경하고 있었습니다.
목록의 정렬 순서(actor_directory)는 0.8.0의 행을 commit 수가 많은 순으로 다시 정렬하여 grift verify에 통과시키면 MISMATCH: 1 field(s) differ와 함께 종료 코드 1이 반환됩니다. 0.7.2에서 저장한 리포트를 0.8.0으로 검산하면 정의 버전이 다르기 때문에 CANNOT_VERIFY가 됩니다. 활동 일수에 대한 주의 문구는 0.8.0에서는 activity.limitations 및 change_rhythm.limitations에 기재되었으며, 0.7.2에는 없었습니다.
프로젝트 선언에는 다음 파일을 사용했습니다.
schema_version = "tep-project-v1"
project_id = "example-python-lib-maintenance"
title = "Python ライブラリの保守(架空の案件)"
[requirements.change_rhythm]
active_days_180d_min = 12
median_gap_days_max = 7
[requirements.surfaces]
required = ["backend", "test"]
[requirements.verification]
required = ["unit"]
[requirements.inputs]
required = ["git", "forge"]
grift project click --requirements python-lib-maintenance.toml --format both --out project/click
출력 결과는 ‘프로젝트 측 선언’과 ‘관측된 수치’라는 두 개의 섹션으로 나뉘며, 선언하지 않은 항목은 not_declared(프로젝트 측에서 명시하지 않음. 부족함이 아님)로 처리되었습니다. 축별로 선언과 관측치를 대조하는 것은 grift align이며, 일치·범위 외·0건·미관측·요구 없음의 5가지 형태로 출력됩니다.
참고 자료
- grift-cli(GitHub, MIT) - CLI 소스 코드. 공식 공개 버전은 0.7.2이며, 0.8.0은 출시 준비 중
- Grift - 제품 사이트
- TEP 페이지(Grift) - TEP에 대한 상세 설명
- grift 리포트 읽는 법(metrics-guide) - 지표별 알기 쉬운 해설
- TEP 이용 규범(norms) - 부재를 부정적으로 해석하지 않음, 가중치 부여 및 환산 금지
- ‘점수도 순위도 매기지 않는다’를 구현에서 어떻게 지켜내는가(Cor.주식회사 블로그, 2026년 10월 25일) - 0.8에서 확정한 5가지 조건
- ‘아, 전해졌다’를 일상으로 만들기 위해, 나는 회사를 만들었다(Cor.주식회사 블로그) - 대표의 이야기와 Grift가 탄생한 배경 철학
- Ethical Use of the MBTI(The Myers & Briggs Foundation) - MBTI 사용 원칙(자발적 참여 원칙, 채용 목적 사용 금지)
- MBTI Basics(The Myers & Briggs Foundation) - 4가지 선호 지표와 16가지 유형
- pallets/click - 측정한 OSS(HEAD
36baa15) - pallets/flask - 측정한 OSS(HEAD
d318b68) - encode/httpx - 측정한 OSS(HEAD
b5addb6) - tj/commander.js - 측정한 OSS(HEAD
ba6d13d)
이 글의 내용을 회사에서 진행하고 싶다면
인재 소개 회사・SES 기업을 위한 Grift 시범 도입(PoC) 상담은 AI 접수 「Cloudia」에서 받고 있습니다.
Support this article
If this article was helpful, please support us with a tip. You can choose any amount.
관련 글
'점수도 순위도 매기지 않는다'를 구현에서 어떻게 지킬 것인가. Grift CLI가 다음 버전에서 정한 5가지 조건
Grift CLI는 점수나 순위를 매기지 않겠다고 약속하고 있습니다. 2026년 10월 대조 작업에서, 주석에는 순위가 아니라고 적혀 있으면서도 표는 커밋 수가 많은 순서대로 정렬되어 있었던 점이 발견되었습니다. 다음 버전(0.8)에 부여할 5가지 인수 조건을 발주사·SES 영업·엔지니어 분들을 위해 알기 쉽게 작성합니다.
AI 개발·수탁 개발 견적이 개인 역량에 의존하게 되는 이유 ~ 근거를 회사의 자산으로 바꾸는 방법
수탁 개발 견적이 사람마다 달라지는 이유와 GitHub 실적, 시장 시세, 공수 내역을 활용하여 설명 가능한 견적 근거를 구축하는 방법을 설명합니다. Grift 활용에 대한 접근법도 소개합니다.
AI 기반 개발(AI 주도 개발)이란? 속도뿐만 아니라 프로덕션 품질을 높이는 개발 체제 구축 방법
AI 기반 개발을 단순한 코드 생성에 그치지 않고, 요구사항 정의, 리뷰, 테스트, 운영에 이르기까지 프로덕션 품질로 내재화하는 접근 방식을 설명합니다. AI 개발을 내재화하고자 하는 기업을 위한 글입니다.