In Front of an Unfamiliar System
Customer, order, active - three systems count three different things
한국어 원문으로 표시합니다.
목표
고객이 "고객"·"활성"·"주문" 이라 부르는 것이 세 시스템에서 각각 무엇인지 대조표로 굳히고, 같은 이름이 가리키는 집합의 크기와 겹침을 자료로 잰다. 식별자 정규화를 바꾸면 답이 통째로 달라진다는 것을 직접 보고, 같은 이름 다른 집합과 다른 이름 같은 집합을 갈라 보고서로 낸다.
왜 중요한가
회의에서 "활성 고객이 몇 명이죠" 라고 물으면 세 사람이 세 숫자를 답하는데 셋 다 맞을 수 있다. 영업은 상태 글자가 A 인 행을, 청구는 청구 가능한 계정을, 운영은 최근에 로그인한 사람을 센 것이다. 세 정의는 각자의 업무에서 옳고, 틀린 것은 하나의 낱말이 세 정의를 다 담고 있다고 믿은 쪽이다. 이 어긋남은 오류로 드러나지 않는다. 쿼리는 성공하고 보고서는 인쇄된다. 드러날 때는 이미 그 숫자로 결정이 내려진 뒤다. 그래서 첫 주에 용어-식별자 대조표를 파일로 만들어 두고, 집계 도구가 그 파일을 읽게 한다. 집합을 견주려면 "같은 것" 이 무엇인지부터 정해야 한다. RFC 5321 2.4 절은 메일 주소의 로컬 파트를 대소문자를 가려 다루라고 정하고 도메인은 가리지 않는다고 적는다. 규격대로 보면 겹치는 사람이 한 명도 없고, 전부 소문자로 눕히면 거의 다 겹친다 — 같은 데이터에서 두 답이 나온다. 채점기는 여러분이 적어 낸 문구를 믿지 않는다. 매번 다른 표 이름과 값으로 만든 데이터베이스에 여러분의 집계기를 실제로 돌려 집합 크기와 겹침을 직접 계산한 값과 대조한다.
단계
- /root/glossary/gen_systems.py 를 만들어 실행해 /root/glossary/systems.db 를 만드세요. 영업(crm)·청구(bill)·운영(ops) 세 시스템의 표 여섯 개가 들어갑니다.
- /root/glossary/terms.json 에 용어-식별자 대조표를 적으세요. 고객·활성·주문 세 용어 × 세 시스템 = 아홉 줄이고, 줄마다 system·table·id_column·predicate 를 적습니다.
- /root/glossary/census.py 를 만들어 대조표의 줄마다 집합 크기를 재고 /root/glossary/census.json 을 쓰게 하세요.
--overlap <경로>를 더해 한 용어 안에서 시스템 두 개씩 견준 결과를 쓰게 하세요. 겹친 수와 한쪽에만 있는 수를 냅니다.--normalize none|strict|loose를 더하세요. strict 는 공백을 떼고 도메인만 소문자로, loose 는 공백을 떼고 전부 소문자로 눕힙니다.- loose 로 잰 값으로 /root/glossary/conflicts.json 을 만들어 용어마다 가장 어긋나는 시스템 쌍과 자카드 계수를 적으세요.
- /root/glossary/naming.json 에 같은 이름 다른 집합(자카드 0.1 이하)과 다른 이름 같은 집합(고객 용어의 칼럼 쌍 중 자카드 0.5 이상)을 갈라 적으세요.
- /root/glossary/glossary_report.md 에 네 절로 보고하세요.
참고
- 실행 계약:
python3 /root/glossary/census.py --db <DB> --terms <대조표> --out <집계 JSON> [--overlap <겹침 JSON>] [--normalize none|strict|loose]는 한 줄 요약을 표준출력에 내고 종료 코드 0 으로 끝납니다. 입력을 읽을 수 없으면 3 입니다. - 대조표:
{"entries": [{"term": …, "system": …, "table": …, "id_column": …, "predicate": "SQL 조건", "note": …}]}. predicate 는WHERE뒤에 그대로 붙는 조건 문자열이고, 조건이 없으면1=1입니다. - 집계 JSON:
{"normalize": …, "counts": [{"term", "system", "table", "rows", "distinct_ids"}]}. counts 는 term, system 오름차순입니다. rows 는 조건에 맞는 행 수, distinct_ids 는 정규화한 식별자의 가짓수입니다. - 겹침 JSON:
{"normalize": …, "pairs": [{"term", "left", "right", "both", "left_only", "right_only"}]}. 한 용어 안에서 시스템 이름 오름차순으로 두 개씩 묶고, left 가 right 보다 앞섭니다. - 정규화: none 은 값 그대로, strict 는
공백 제거 + 마지막 @ 뒤만 소문자, loose 는공백 제거 + 전부 소문자입니다. - conflicts.json:
{"normalize": "loose", "terms": [{"term", "sizes": {시스템: 크기}, "min_pair": [시스템, 시스템], "min_jaccard": 소수점 셋째 자리, "conflict": true|false}]}. 자카드는 교집합 크기를 합집합 크기로 나눈 값이고, 합집합이 비면 1.0 으로 봅니다. conflict 는 min_jaccard 가 1.0 미만일 때 참입니다. - naming.json:
{"same_name_different_thing": [{"term", "min_pair", "jaccard"}], "different_name_same_thing": [{"a", "b", "jaccard"}]}. a 와 b 는시스템.표.칼럼꼴이고 a 가 b 보다 앞섭니다. - 흔한 실수: 대조표에 조건을 빼먹기(활성의 차이는 표가 아니라 조건에 있습니다), 정규화 규칙을 집계마다 다르게 쓰기, 겹침을 세기 전에 중복을 없애지 않기.
- 자카드 문턱값 0.1 과 0.5, 그리고 소수점 셋째 자리 반올림은 이 실습의 가정입니다. 표준이 정해 주는 값이 아니라 보고서에 적어 두고 쓰는 값입니다.
- 참고 문서: RFC 5321 2.4 절은 메일 주소의 대소문자 규칙을, RFC 4949는 같은 낱말을 여러 뜻으로 쓰는 문제를 다루는 용어집의 본보기를, SQLite SELECT 문서는 INTERSECT 와 EXCEPT 를 설명합니다.
시스템 세 대를 손에 쥐기
/root/glossary/gen_systems.py 를 만들어 실행해 /root/glossary/systems.db 를 만드세요. crm_customer·crm_order·bill_account·bill_invoice·ops_user·ops_workorder 여섯 표가 들어갑니다.
현장에서는 세 시스템에서 각각 추출본을 받습니다. 여기서는 그 셋을 한 파일에 담습니다. 표 이름 앞의 crm·bill·ops 가 어느 시스템에서 온 것인지 알려 줍니다. 만든 뒤 sqlite3 로 표 목록과 몇 행씩만 먼저 보세요.
용어-식별자 대조표 만들기
/root/glossary/terms.json 에 아홉 줄을 적으세요. 용어는 고객·활성·주문 셋, 시스템은 crm·bill·ops 셋입니다. 줄마다 term·system·table·id_column·predicate 를 적고, 활성은 같은 시스템의 고객과 같은 표를 쓰되 조건으로 좁힙니다. 주문은 고객과 다른 표입니다.
조건이 빠지면 대조표는 절반만 쓸모가 있습니다. 활성의 차이는 표가 아니라 조건에 있기 때문입니다. 각 시스템이 활성을 무엇으로 가르는지는 표를 열어 보면 보입니다 — 상태 글자, 청구 가능 여부, 마지막 로그인 날짜입니다. 조건이 없는 줄은 predicate 를 1=1 로 둡니다.
같은 이름의 집합 크기 재기
/root/glossary/census.py 를 만들어 대조표의 줄마다 조건에 맞는 행 수(rows)와 식별자 가짓수(distinct_ids)를 재고 /root/glossary/census.json 에 쓰게 하세요. counts 는 term, system 오름차순입니다.
predicate 는 WHERE 뒤에 그대로 붙는 조건 문자열입니다. 행 수와 식별자 가짓수를 따로 세는 이유는 한 사람이 여러 행을 가질 수 있기 때문입니다. 이 단계에서는 값을 손대지 않고 그대로 비교합니다 — 정규화는 5단계에서 붙입니다.
두 시스템씩 견주기
--overlap <경로> 를 더해 한 용어 안에서 시스템 두 개씩 견준 결과를 쓰게 하세요. both 는 양쪽에 다 있는 식별자 수, left_only 와 right_only 는 한쪽에만 있는 수입니다. 이 단계에서도 값은 그대로 비교합니다.
용어마다 시스템 이름을 오름차순으로 정렬해 두 개씩 묶습니다. 세 시스템이면 세 쌍입니다. 값을 그대로 비교하면 겹침이 거의 0 으로 나올 텐데, 그 결과 자체가 다음 단계의 출발점입니다 — 왜 0 인지 눈으로 확인하세요.
무엇을 같다고 볼 것인가
--normalize none|strict|loose 를 더하세요. strict 는 공백을 떼고 마지막 @ 뒤만 소문자로 눕히고, loose 는 공백을 떼고 전부 소문자로 눕힙니다. 집계 JSON 과 겹침 JSON 의 normalize 칸에 쓴 값을 적습니다.
RFC 5321 2.4 절은 메일 주소의 로컬 파트를 대소문자를 가려 다루라고 정하고 도메인은 가리지 않는다고 적습니다. strict 는 그 규격을 따르는 쪽이고 loose 는 이 고객사 시스템들이 실제로 하는 일입니다. 같은 데이터에서 두 답이 나오는 것을 직접 보세요.
같은 이름이 다른 집합을 가리킨다
loose 로 잰 값을 써서 /root/glossary/conflicts.json 을 만드세요. 용어마다 시스템별 집합 크기(sizes), 자카드가 가장 낮은 시스템 쌍(min_pair), 그 값(min_jaccard, 소수점 셋째 자리), conflict 여부를 적습니다.
자카드는 교집합 크기를 합집합 크기로 나눈 값입니다. 합집합이 비면 1.0 으로 봅니다. 가장 낮은 쌍이 여럿이면 시스템 이름 오름차순으로 앞선 쌍을 고릅니다. conflict 는 min_jaccard 가 1.0 미만일 때 참입니다 — 조금이라도 다르면 같은 이름을 쓰는 것이 위험하다는 뜻입니다.
다른 이름이 같은 것을 가리킨다
/root/glossary/naming.json 에 두 목록을 적으세요. same_name_different_thing 은 min_jaccard 가 0.1 이하인 용어이고, different_name_same_thing 은 고객 용어의 세 칼럼 쌍 중 자카드가 0.5 이상인 쌍입니다. 칼럼은 시스템.표.칼럼 꼴로 적고 a 가 b 보다 앞섭니다.
같은 이름 다른 것보다 다른 이름 같은 것이 더 흔하고 더 위험합니다. 이름이 다르니 아무도 대조하지 않고, 그래서 같은 사람이 세 시스템에 세 번 들어 있다는 것을 아무도 모릅니다. 자카드는 6단계에서 쓴 것과 같은 정의이고 정규화도 loose 로 같습니다.
무엇을 합의할지 적기
/root/glossary/glossary_report.md 에 ## 세 시스템이 같은 말을 쓴다 ## 용어-식별자 대조표 ## 같은 이름 다른 집합 ## 합의할 것 네 절로 적으세요. 세 용어의 이름과 시스템별 집합 크기가 모두 나와야 하고, 쓴 정규화 규칙도 적습니다.
보고서는 손으로 쓰지 말고 census·conflicts·naming 세 파일에서 만들어 내세요. 그래야 대조표가 바뀔 때 보고서도 함께 바뀝니다. 마지막 절에는 통일하자는 제안이 아니라 '보고서마다 어느 정의를 썼는지 적자' 는 합의를 적으세요.