Skip to content

Releases: maxidea1024/tabbit

Release list

v0.1.0

Choose a tag to compare

@github-actions github-actions released this 26 Aug 09:19

첫 릴리즈입니다. 아래가 최근에 바뀐 것이고, 도구 전체의 모습은 절 끝의
담긴 것에 있습니다.

  • 샘플이 전부 합성 데이터가 되었습니다. 검증에 쓰던 상용 프로젝트의 워크북을 들어내고,
    같은 규모와 같은 표기를 재현하는 가상 코퍼스로 바꿨습니다
    (샘플).

    • sprout — 출시 전 소규모. 워크북 17개·테이블 71개·109,218행. 이 도구가 설계하지
      않은 규칙으로 쓰인 시트를 그대로 읽는 쪽이고, 변환하면 무엇이 나오는가의 답입니다 —
      지원하는 모든 언어의 산출물이 커밋되어 있습니다
    • canopy — 라이브 대규모. 워크북 42개·정의된 이름 549개·셀 873만. 테이블의 경계가
      워크북의 정의된 이름인 레이아웃이고, 중첩 컬럼·매트릭스 표·지역 변종·제약 행을 전부
      담습니다. 같은 코퍼스가 .xlsx.xlsb 양쪽에 있어 두 리더의 결과가 같아야 하는
      게이트
      로 섭니다
    • 값이 아니라 분포를 재현합니다. 정본은 schema/*.tsv이고 워크북은 생성기가 만듭니다.
      표기와 값이 갈라져 있어, 레이아웃을 읽는 방식이 바뀌면 그 파일들의 diff로 드러나고
      데이터가 바뀌면 드러나지 않습니다
    • 벤치마크를 전면 재측정했습니다. 데이터셋이 바뀌었으므로 파일 크기·로드 시간·CPU·
      메모리 전부 다시 쟀고, 기준이 바뀐 사실을 문서 앞에 적었습니다
      (벤치마크)
  • 찾은 문제를 로그가 아니라 보고서로 냅니다. 실행이 끝나면 HTML 한 장과 JSON 한 장을
    남기고, 경고 이상이면 브라우저로 엽니다
    (사용 · 설계).

    • 멈춘 실행이 본론입니다. 타깃은 임포트·쿠킹·검증을 전부 통과해야 도달하는데, 이
      산출물이 가장 필요한 실행은 거기까지 가지 못한 실행입니다. 그래서 타깃이 아니라 실행 자체에
      붙어 있고, 예외로 끝난 경로에서도 씁니다. 종료 코드에는 관여하지 않습니다.
    • 구글 시트의 셀은 클릭 한 번입니다. 위치가 이미 셀 단위 딥링크였고, 그것이 로그에서
      버려지고 있었습니다. xlsx는 셀을 여는 이식 가능한 URL이 없으므로 링크인 척하지 않고
      위치 텍스트와 복사 버튼을 냅니다.
    • 누적을 수치로 보입니다. 직전 리포트와 대조해 신규 · 지속 · 해소를 셉니다. 대조는
      참고이지 판정이 아니어서 종료 코드에도 검증에도 관여하지 않습니다 — 시트에 행이 끼어들면
      같은 문제가 신규+해소 한 쌍으로 나타나기 때문이고, 그 한계는 페이지에 적혀 있습니다.
    • 겉모습은 GitHub Primer입니다 — 색 토큰 · 서체 · 박스 · 알약 라벨 · 밑줄 내비게이션 ·
      버튼까지. 이 페이지를 읽는 사람은 하루의 대부분을 그렇게 생긴 화면 앞에서 보내고,
      도구마다 제 나름의 회색 상자 방언을 쓰면 내용을 읽기 전에 방언부터 익혀야 합니다.
      검색은 찾은 자리를 표시하고, 검색창에는 지움 버튼이 있습니다.
    • 행에서 앞자리는 내용입니다. 무엇이 잘못됐는지가 먼저 오고 위치는 행 끝입니다 —
      위치는 맥락이지 내용이 아닌데 맨 왼쪽 고정폭 자리를 차지하고 있었습니다. 보고가 백틱으로
      인용한 이름은 코드로 놓이고(그 이름이 윗 행과 다른 유일한 부분입니다), 모든 위치가
      공유하는 폴더는 머리글에서 한 번만 말합니다.
    • 복사 버튼은 보고 전체를 담습니다 — 문장, 그 아래 위치, 구글 시트면 셀을 여는 링크,
      그리고 메시지 ID. 콘솔이 찍는 형태 그대로라 동료에게 그대로 보낼 수 있습니다. 위치만
      복사하던 것은 아무도 보내지 않는 것이었습니다.
    • 목록은 한 번에 하나, 행은 한 줄입니다. 문제 · 알려진 문제 · 해소됨 · 기록은 탭이고,
      행은 한 줄로 잘려 클릭하면 펼쳐집니다 — 보고 하나는 문단이고 그런 문단 14개는 벽인데
      행마다 다른 부분은 문장 앞쪽에 있기 때문입니다. 메시지 ID는 닫힌 행에 없습니다:
      CI가 필터하는 이름이지 시트를 가진 사람이 할 수 있는 일이 아니라서, 펼친 행과 종류별
      묶기의 머리글에만 둡니다.
    • 평면 목록이 아니라 워크북·시트로 묶입니다. 한 실행이 5,831건을 낸 적이 있고, 그 규모의
      평면 목록은 벽입니다. 행 하나짜리 자리는 그룹을 만들지 않고 그냥 행입니다 — 실측에서
      시트 12개가 각각 1건이었고, 그러면 항목마다 머리글을 하나씩 무는 평면 목록이 됩니다.
      묶는 축은 둘이고(시트별은 일하는 순서, 종류별은 이해하는 순서) 전환은 클릭 하나입니다.
    • 보는 사람이 없으면 열지 않습니다. CI 환경 변수 · 리다이렉트된 출력 · --silent
      설정보다 우선합니다. 마지막 리포트는 --show-report로 변환 없이 다시 엽니다.
    • 새 검출은 하나도 추가하지 않았습니다. 단계마다 수집되어 인쇄되고 버려지던 것을 남길
      뿐이고, 콘솔과 파일 로그는 그대로입니다.
  • 바뀐 것이 없으면 아무것도 하지 않습니다. 지난 실행이 무엇을 읽고 무엇을 썼는지 기록해
    두었다가 비교하고, 전부 그대로면 즉시 종료합니다
    (사용 · 설계).

    • 실측이 먼저였습니다. 테이블 548개·워크북 36개(1,149 MB)를 7개 타깃으로 내는 실행이
      161초이고, 그 절반이 임포트와 쿠킹, 나머지 절반이 binary·json 익스포트입니다 —
      코드 생성 5개 언어는 합쳐 7.5초입니다. 어느 한쪽만 캐시해도 절반밖에 줄지 않으므로
      양쪽을 함께 건너뜁니다.
    • 키가 셋입니다. recipe의 전역 설정과 입력이 모델을 정하고, Validation 섹션이 검증을,
      Targets 항목 하나하나가 그 항목의 산출을 정합니다. 그래서 타깃 하나의 설정을 고친 것이
      워크북 36개를 다시 읽을 이유가 되지 않습니다
      — 그 항목만 다시 냅니다.
    • 수정 시각만 바뀐 것은 바뀐 것이 아닙니다. 크기와 시각이 어긋난 파일만 해시해서
      내용으로 판정합니다. git checkout은 받은 파일 전부의 수정 시각을 지금으로 바꾸므로,
      시각만 보는 캐시는 체크아웃 한 번을 넘기지 못합니다.
    • recipe의 주석과 공백, 설정 순서는 키에 들어가지 않습니다. 파싱된 문서를 정규화해서
      해시하므로, 제외 목록에 이유를 적어 넣는 것이 변환 한 번의 값이 되지 않습니다.
    • 디렉터리 목록도 기록합니다. 워크북이 하나 추가된 것은 기존 어느 파일도 바꾸지
      않으므로, 파일 목록만으로는 보이지 않습니다.
    • 강제가 둘입니다. --full은 캐시를 의심할 때(입력부터 전부 다시), --force-output
      캐시를 믿으면서 산출물만 다시 원할 때입니다. --validate-only와 함께 쓰는 것은 거절합니다.
    • 건너뛴 항목의 파일은 「이 실행이 쓴 것」에 포함됩니다. 스윕은 이 실행이 쓰지 않은 생성
      파일을 지우므로, 이것이 없으면 캐시가 맞다고 판정한 파일을 그 실행이 전부 지웁니다.
    • 건너뛰지 않는 것. 파일을 하나도 쓰지 않는 항목입니다 — 데이터베이스 익스포트와
      히스토리 기록이 그렇습니다. 산출물을 해시해서 확인할 수 있는 것만 건너뜁니다. 그리고
      히스토리·요약 타깃이 있는 recipe는 커밋 식별자가 키에 들어가므로, 새 커밋은 전체 실행입니다.
    • 검증은 캐시를 쓰지 않습니다. --validate-only가 「지난번에 통과했다」로 통과하면
      게이트가 아닙니다.
    • 왜 전체를 다시 하는지 항상 말합니다. 어느 워크북이 바뀌었는지, recipe의 어느 쪽이
      바뀌었는지, 다른 빌드가 쓴 캐시인지. 이유를 대지 못하는 캐시는 --full이 습관이 되어
      없는 것과 같아집니다.
    • 구글 시트는 Drive의 version으로 판정합니다. 문서는 크기도 수정 시각도 없으므로
      drive.metadata.readonly 스코프를 더 받아 카운터 하나를 읽습니다. 셀은 읽지 않습니다.
      물어볼 수 없으면 바뀐 것으로 보고 가져오고, 무엇을 허용하면 되는지와 어느 파일을 지우면
      동의를 다시 받는지까지 출력합니다.
    • 건너뛴 실행도 낡은 생성 파일은 지웁니다. 아무것도 하지 않고 끝나면 스윕에 도달하지
      못하므로, 「테이블을 지웠을 때 그 파일이 없어지는가」가 그날 다른 것이 바뀌었는지에
      달리게 됩니다. 이것을 잡은 것은 기존 스윕 게이트입니다 — 캐시가 「건너뛴다」고 보고하며
      파일을 남겼습니다.
    • --detailed-exit-code로 할 일이 없던 실행을 구분합니다. 종료 코드 2입니다. 다음
      단계가 배포인 파이프라인이 쓰는 형태이고, 플래그 뒤에 둔 이유는 호환입니다 — 기본으로
      0이 아닌 값을 내면 뒤에 단계를 이어 붙인 스크립트가 캐시가 처음 동작한 날 멈춥니다.
    • 캐시는 커밋 대상이 아닙니다. 절대 경로와 그 기계의 파일 상태를 담습니다.
  • 실행이 여는 두 줄에 버전을 적습니다. 도구 빌드가 한 줄, .tcb 형식 번호와 .NET
    런타임과 플랫폼이 다음 줄, 그 아래 빈 줄입니다 — 넷을 한 줄에 담으면 아무것도 찾을 수 없는
    줄이 되고, 빈 줄이 없으면 그 뒤 수백 줄의 앞 두 줄이 됩니다. 받은 로그에 대해 묻게 되는
    것이 대개 이 넷 중 하나이고, 그중 형식 번호가 유일하게 읽는 쪽과 어긋날 수 있는
    입니다. 빌드 문자열은 빌드 캐시의 키에 쓰는 것과
    같은 값이라 한 곳에서 나옵니다 — 「다른 빌드가 쓴 캐시입니다」라는 보고와 첫 줄이 어긋나면
    아무도 무엇을 해야 할지 알 수 없습니다. 표준 출력이 남의 입력인 실행
    (--new-encryption-key, --out 없는 조회)에는 적지 않고 파일 로그에만 남깁니다.

  • 실행이 단계별 소요 시간을 스스로 말합니다. 임포트·쿠킹·검증·산출·커밋과, --verbose에서는
    타깃별로. 지금까지는 총 소요만 나왔으므로 어디가 느린지 알려면 종료 지점을 바꿔 세 번 돌리고
    로그의 타임스탬프를 손으로 빼야 했습니다.

  • 명령줄 옵션마다 캐시에 대한 뜻을 선언합니다. --verbose는 산출을 바꾸지 않으므로 캐시를
    버리지 않고, --target-side는 바꾸므로 키에 들어갑니다. 선언이 없는 옵션이 있으면 테스트가
    실패합니다
    — 분류를 잊은 결과가 「조용히 낡은 산출」이 아니라 「빌드가 안 됨」이어야 합니다.

  • 로그 한 줄이 수준과 단계를 먼저 말합니다. [W] [Cooking ] ... 형식이고, 콘솔과 파일이
    같은 구성입니다 — 콘솔은 지켜보는 동안 읽는 것이라 수준을 한 글자로, 파일은 나중에 읽는
    것이라 시각과 함께 세 글자로 적습니다 (보기).

    • 단계는 그 줄을 쓴 클래스가 밝힙니다. 호출 스택에서 미루어 짐작하는 것이 아니라
      클래스마다 한 줄로 적어 둡니다. Loading·Importing·Cooking·Validating·Exporting·
      Committing·Recording 일곱 가지이고, 밝히지 않은 줄은 Tabbit으로 나갑니다.
    • 메시지 쪽은 하나도 손대지 않았습니다. 선언한 이름이 정적 Log를 가리므로 기존 호출
      132곳이 그대로입니다.
  • 시트의 날짜를 어느 시간대로 읽을지 recipe에 적습니다. TimeZone이 그것이고, 저장되는 값은
    언제나 UTC입니다 — 이 설정이 정하는 것은 시트에 적힌 시각을 어느 시간대의 것으로 읽을지 하나뿐입니다
    (설정 ·
    설계).

    • 지역 이름과 고정 오프셋을 모두 받습니다. Asia/Seoul·Korea Standard Time 같은 이름은
      서머타임을 포함한 그 지역의 역사를 따르고, +09:00·+0900·+09·Z는 일 년 내내 같습니다.
      후자는 기계에 시간대 데이터가 없어도 되므로, 컨테이너에서 도는 변환이 이름 조회에 매이지
      않습니다.
    • 소스 항목별로 다르게, 명령줄로 강제. 항목의 TimeZone이 recipe 전체 설정보다 우선하고,
      --time-zone그 둘 다를 덮어씁니다 — recipe가 시간대를 잘못 적고 있는 실행을 위한
      것이므로, 덮어쓸 대상이 바로 그 항목별 설정입니다. 적용한 값은 실행 로그에 한 줄로 남습니다.
    • 오프셋을 적은 셀이 실행 기계에 따라 달라지던 것을 고쳤습니다. 2022-01-24T10:30:00Z
      변환을 도는 기계의 시간대로 옮겨져 읽혔습니다 — KST PC에서는 19:30, UTC 러너에서는 10:30이
      되었고, 어느 쪽도 그 사실을 말하지 않았습니다. 이제 셀이 적은 오프셋이 그 값을 정하고,
      recipe 설정보다 우선합니다.
    • 서머타임의 두 자리. 시계가 건너뛴 시각은 그 지역에 존재하지 않았으므로 셀 위치와 함께
      거절합니다. 두 번 지나간 시각은 표준시 쪽으로 읽고 그런 셀이 몇 개였는지 보고합니다.
    • 비워 두면 지금까지와 같습니다. 셀이 이미 UTC로 적힌 것으로 보므로 값이 달라지지 않고,
      골든도 한 바이트도 바뀌지 않았습니다. 저장 타입의 크기(초 단위·32비트)는 별도 검토입니다.
  • HTML 문서를 데이터 확인 도구로. 생성되는 페이지 구성과 항해가 바뀌었습니다. 데이터·형식·
    생성기는 그대로이고, 바뀐 것은 이 타깃의 산출물뿐입니다
    (가이드 · 설계).

    • 테이블당 페이지 하나입니다. 전부 한 페이지였고, 최대 테이블이 10만 행인 워크북에서 그
      페이지가 36.9 MB였습니다 — 그 테이블 하나 때문에 나머지 66개를 볼 수 없었습니다.
      MaxRowsPerTable(기본 1,000, 0은 무제한)이 페이지가 보여주는 행 수를 정하고, 적용되면
      몇 행 중 몇 행인지 페이지에 적힙니다.
    • 모든 페이지에 상단 바·브레드크럼·형제 목록이 있습니다. 예전에는 상세 페이지에서 나가는
      링크가 하나도 없어 브라우저 뒤로가기가 유일한 수단이었습니다. 목록이 페이지 안에 있으므로
      파일 하나만 전달받아도 이동이 됩니다.
    • 전체 윤곽을 개요가 제시합니다. 테이블·행·컬럼·enum·레이블·상수·셀 개수와, 컬럼의
      타입별·역할별·측별 분포, 최대 테이블 목록입니다. 여기에 전체 컬럼 색인(fields.html)이
      더해집니다 — 같은 컬럼 이름의 타입이 어긋난 곳을 이름 정렬로 찾을 수 있습니다.
    • enum 값은 커서를 올리면 enum 전체가 카드로 나타납니다. 이동하지 않고 확인됩니다.
      정의는 페이지마다 한 번만 싣습니다 — 칸마다 title에 담으면 10만 행 테이블에서 enum 전체가
      10만 번 반복됩니다.
    • 참조와 사용처가 양방향입니다. 테이블 페이지가 자기를 가리키는 컬럼을, enum 페이지가
      자기를 쓰는 컬럼을 함께 냅니다.
    • 표에 필터와 정렬(5,000행까지)이 붙고, 빈 문자열·값 없음·빈 배열이 구분되어 표시되고,
      키 컬럼이 가로 스크롤에서 고정됩니다. 폐기된 font·align 마크업이 CSS로 바뀌면서
      어두운 테마도 따릅니다. 외부 요청은 계속 0개입니다.
    • 테마를 고를 수 있습니다. 상단 바의 버튼이 시스템 → 밝게 → 어둡게를 순환하고 선택은
      localStorage에 남습니다. 페이지가 그려지기 전에 적용되므로 이동할 때 다른 테마가
      번쩍이지 않습니다.
    • 종류마다 목록 페이지. tables.html · fields.html · enums.html ·
      constantsets.html이 각각 정렬·필터되는 목록이고, 개요는 카운터와 분포만 남습니다 —
      목록을 개요에 두면 프로젝트가 커질수록 카운터 아래가 이름의 벽이 됩니다.
    • 아이콘과 브랜드 마크. 테이블·컬럼·enum·상수 세트·워크북·시트에 인라인 SVG 심볼을
      붙였습니다(이모지가 아닌 것은 플랫폼마다 다른 그림이 되기 때문입니다). 상단 바에 브랜드
      마크가 들어가고, 스크롤바도 얇은 것으로 지정합니다.
    • 중첩·옵셔널 시트를 문서화합니다. 이 타깃은 네 가지 형태(레코드 그룹 · 다중 중첩 ·
      옵셔널 필드 · 옵셔널 원소) 중 어느 것도 선언하지 않고 있었습니다 — 그래서 그런
      워크북은 문서가 한 장도 생성되지 않았고, 그것이 데이터를 들여다볼 필요가 가장 큰 시트
      입니다. 컬럼을 그리는 타깃이라 구현이 필요한 것은 없었고, 선언과 그룹 이름을 읽는 자리
      하나였습니다.
    • 헤더와 키 컬럼이 고정됩니다. 표가 페이지가 아니라 자기 컨테이너 안에서 스크롤되므로
      값을 보면서 컬럼 이름을 잃지 않습니다. 헤더 행 높이를 고정해 스택이 첫 값을 덮던 것도
      함께 고쳤고, 설명이 하나도 없는 시트에서는 설명 행과 Description 열을 그리지 않습니다.
    • 참조 값이 그 행으로 갑니다. 키가 적혀 있는데 그 행을 찾는 방법이 없었습니다. 대상이
      여럿인 컬럼은 후보 테이블을 함께 내고 읽는 사람이 고릅니다. 행 상한 때문에 그 페이지에
      없는 행이면 페이지까지만 가리킵니다 — 없는 앵커를 만들지 않습니다.
    • 참조 그래프 페이지(references.html)를 추가했습니다. 테이블에 커서를 올리면 그
      테이블의 간선만 남습니다 — 실측 노드 323개·간선 637개에서 47개만 남으므로, 수백 개가
      겹치는 가운데에서도 읽힙니다. 층으로 배치해 모든 화살표가 앞을
      향하고, 자기 참조는 고리입니다. 좌표는 생성기가 계산하고 페이지는 인라인 SVG를 담습니다 —
      레이아웃 라이브러리를 싣지 않으므로 매번 같은 그림이고 커밋해서 diff할 수 있습니다.
    • 페이지의 문구가 한국어입니다. 시트에서 온 이름과 설명은 그대로이고, 타입 이름과 측
      표기(c·s·cs)는 recipe의 어휘라 번역하지 않습니다.
    • 목록의 기본 정렬은 이름 오름차순입니다 — 테이블·컬럼·enum·상수 세트 모두, 대소문자를
      가리지 않고. 서수 정렬은 대문자를 모두 소문자 앞에 두므로 찾는 이름이 예상한 자리에 없습니다.
    • 참조 그래프를 탐색기로. 끌어서 이동하고 휠로 확대하며, 테이블을 누르면 그 테이블의
      이웃만 그려집니다 — 왼쪽이 가리키는 테이블, 오른쪽이 가리켜지는 테이블이고, 이웃을 다시
      눌러 걸어갈 수 있습니다. 그림은 변환된 그룹 안에 있으므로 이동이 요소 하나의 속성 하나이고,
      호버 강조는 간선 전체를 담은 그룹의 불투명도 하나를 바꿉니다. 아래에 연결 정도 표를
      두어 어디서부터 볼지 정하게 했습니다.
    • 스크롤 영역은 페이지당 하나입니다. 표와 페이지가 함께 ...
Read more