OPEN_GRID v0.2.0 — 오늘 하루 만에 3,032줄 코드를 917줄로 줄인 이야기

2026. 06. 02  ·  OPEN_GRID

안녕하세요! 오늘 OPEN_GRID v0.2.0을 공개합니다.

OPEN_GRID는 AUI Grid 같은 상용 그리드를 대체할 수 있는 무료 오픈소스 데이터 그리드 라이브러리입니다. Vanilla JS 코어 위에 React, Vue 3, jQuery, AngularJS, Vanilla 5개 프레임워크를 모두 지원합니다.


🏗️ 오늘의 핵심 작업 — 대규모 OOP 리팩토링

v0.2.0의 가장 큰 변화는 핵심 엔진 코드의 전면 재설계입니다.
단 하루 만에 3,032줄짜리 거대 파일 하나12개의 전문 클래스로 분리했습니다.

📊 Before vs After 요약

항목Before (리팩토링 전)After (오늘)
OpenGrid.ts 줄 수3,032줄917줄 (−70%)
클래스 수1개 (모든 것이 한 파일에)13개 (역할별 분리)
단위 테스트354개 PASS354개 PASS ✅
TypeScript 오류0개0개 ✅
코드 가독성“어디에 뭐가 있지?”“이 기능은 이 파일”

🔴 Before — “신 객체(God Object)” 문제

리팩토링 전 OpenGrid.ts는 이런 상태였습니다:

// OpenGrid.ts — 3,032줄짜리 거대 파일
export class OpenGrid {
  // 정렬 상태
  private _sortList: SortItem[] = [];
  // 필터 상태
  private _filters: Record<string, FilterItem[]> = {};
  // 그룹핑 상태
  private _groupFields: string[] = [];
  private _groupExpandedKeys: Set<string> = new Set();
  private _groupFlatRows: Array<GroupRow | T> = [];
  private _isGroupMode = false;
  // 트리 상태
  private _treeRoots: TreeNode[] = [];
  private _treeFlatRows: TreeNode[] = [];
  private _treeExpandedKeys: Set<any> = new Set();
  private _isTreeMode = false;
  // 찾기 바 상태
  private _findBar: HTMLElement | null = null;
  private _findInput: HTMLInputElement | null = null;
  private _findFilter: string = '';
  // 키보드, 클립보드, 내보내기, 푸터, 이벤트, 트리거...
  // 모두 여기 한 곳에! 😱

  // _handleKeyDown() 168줄
  // exportExcel() 111줄
  // _renderFooterEl() 88줄
  // handleCellClick() 71줄
  // _rebuildGroups() ...
  // _rebuildTree() ...
  // (끝없이 계속)
}

문제점:

  • 🔴 파일 하나가 3,032줄 — 어디서 뭘 찾아야 할지 모름
  • 🔴 “정렬 기능 수정하러 들어갔다가 트리 코드와 싸움”
  • 🔴 새 기능 추가할수록 파일이 무한정 커짐
  • 🔴 한 곳을 고치면 다른 곳이 영향받을까 봐 두려움

🟢 After — 각자 맡은 역할만 하는 12개 클래스

리팩토링 후 구조입니다:

// ✅ 지금은 이렇게 깔끔합니다

OpenGrid.ts          (917줄)  ← 총괄 조정자
├── GridRenderer.ts           ← 화면에 그리는 일만
├── RowManager.ts             ← 행 선택/체크만
├── CellEditManager.ts        ← 셀 편집 라이프사이클만
├── CellTypeRegistry.ts       ← 셀 타입 판별만
├── CellEventHandler.ts       ← 셀 클릭/마우스 이벤트만
├── KeyboardManager.ts        ← 키보드/클립보드만
├── SortFilterManager.ts      ← 정렬/필터 상태와 로직만
├── GroupTreeManager.ts       ← 그룹핑/트리 상태와 로직만
├── FindBarManager.ts         ← 찾기 바 UI와 검색만
├── ExportManager.ts          ← Excel/CSV/JSON 내보내기만
├── FooterManager.ts          ← 푸터 집계 계산과 렌더만
└── TriggerManager.ts         ← 이벤트 트리거 훅만

🔍 Before vs After — 구체적인 예시

예시 1 — 키보드 네비게이션

// ❌ Before: OpenGrid.ts 안 어딘가에 168줄짜리 괴물 메서드
private _handleKeyDown(e: KeyboardEvent): void {
  if (this._editMgr.activeEditor) return;
  this._handleCellKeyEvt('cellKeyDown', e);
  const totalRows = this._data.rowCount;
  const totalCols = this._colLayout.visibleLeaves.length;
  if ((e.ctrlKey) && e.key === 'c') { this._copyToClipboard(); return; }
  if ((e.ctrlKey) && e.key === 'v') { this._pasteFromClipboard(); return; }
  // ... 100줄 더 ...
  switch (e.key) {
    case 'ArrowDown': /* ... */ break;
    case 'ArrowUp':   /* ... */ break;
    // ...
  }
}
// ✅ After: KeyboardManager.ts 파일에 깔끔하게 분리
// OpenGrid.ts 에는 단 1줄만 남음
private _handleKeyDown(e: KeyboardEvent): void {
  this._kbdMgr.handleKeyDown(e);  // 끝!
}

// 실제 로직은 KeyboardManager.ts 에서 관리
export class KeyboardManager {
  handleKeyDown(e: KeyboardEvent): void { /* ... */ }
  private _copyToClipboard(): void { /* ... */ }
  private _pasteFromClipboard(): void { /* ... */ }
}

예시 2 — Excel 내보내기

// ❌ Before: OpenGrid.ts 안에 111줄짜리 exportExcel + 관련 헬퍼들
exportExcel(options?: ExportOptions): void {
  // 111줄의 복잡한 로직이 OpenGrid 안에...
  import('xlsx-js-style').then(({ utils, writeFile }) => {
    const rows: any[][] = [];
    // 스타일, 색상, 컬럼 너비, 셀 병합...
  });
}
private _readCssVar(name: string): string { ... }
private _hexToXlsxRgb(hex: string): string { ... }
// ✅ After: ExportManager.ts 파일로 완전 분리
// OpenGrid.ts 에는 위임만
exportExcel(options?: ExportOptions): void {
  this._exportMgr.exportExcel(options);  // 끝!
}
exportCsv(options?: ExportOptions): void {
  this._exportMgr.exportCsv(options);   // 끝!
}
exportSheetsExcel(filename?: string): void {
  this._exportMgr.exportSheetsExcel(filename);  // 끝!
}

예시 3 — 그룹/트리 상태 관리

// ❌ Before: OpenGrid.ts 안에 흩어진 그룹+트리 상태와 메서드들
private _groupFields: string[] = [];
private _groupExpandedKeys: Set<string> = new Set();
private _groupFlatRows: Array<GroupRow | T> = [];
private _isGroupMode = false;
private _treeRoots: TreeNode[] = [];
private _treeFlatRows: TreeNode[] = [];
private _treeExpandedKeys: Set<any> = new Set();
private _isTreeMode = false;
// + _rebuildGroups(), _rebuildTree(), _getSummaryDefs()
// + groupBy(), clearGroup(), expandAll(), collapseAll()
// + enableTree(), disableTree(), expandNodes()... 모두 한 파일에!
// ✅ After: GroupTreeManager.ts 가 그룹/트리 모든 것을 책임
export class GroupTreeManager {
  // 상태 → 이 클래스 안에만
  private _groupFields: string[] = [];
  private _isGroupMode = false;
  private _treeRoots: TreeNode[] = [];
  private _isTreeMode = false;
  // ...

  // 메서드 → 이 클래스 안에만
  groupBy(fields: string[]): void { ... }
  enableTree(): void { ... }
  rebuildGroups(): void { ... }
}

// OpenGrid.ts 는 그냥 전달만
groupBy(fields: string[]): void {
  this._grpMgr.groupBy(fields);  // 끝!
}

💡 왜 이게 중요한가요?

1. “찾기 쉬워졌다”

이제 버그가 생기면 어디서 고쳐야 할지 바로 알 수 있습니다.

  • Excel 내보내기 버그 → ExportManager.ts 열기
  • 키보드 동작 이상 → KeyboardManager.ts 열기
  • 그룹핑 오동작 → GroupTreeManager.ts 열기

2. “안전하게 고칠 수 있다”

각 클래스는 의존성 주입(Deps 인터페이스)으로 연결되어 있어서,
한 클래스를 수정해도 다른 클래스에 영향이 가지 않습니다.

3. “테스트가 쉬워진다”

거대한 God Class는 테스트가 어렵습니다. 작게 분리된 클래스는
각각 독립적으로 테스트할 수 있습니다. 현재 354개 단위 테스트 ALL PASS.

4. “새 기능 추가가 쉬워진다”

앞으로 새 기능을 추가할 때 기존 코드를 거의 건드리지 않고
새 Manager 클래스만 추가하면 됩니다.


✨ 주요 기능

  • 📊 가상 스크롤 — 수만 행도 부드럽게
  • 🔀 정렬 · 필터 — 멀티 정렬, 고급 필터 패널
  • ✏️ 인라인 편집 — text / number / date / select / radio / checkbox
  • 🌳 트리 · 그룹 — 계층형 데이터, 집계 요약
  • 📦 Excel · CSV · JSON 내보내기 — 테마 스타일 포함
  • 🖼️ 셀 병합 · 고정 행·열
  • 웹 접근성 — WCAG 2.5 키보드 네비게이션, aria-live
  • 🎨 컨텍스트 메뉴 · 마스킹 · 워크시트(탭)

🚀 5개 프레임워크 완전 지원

프레임워크데모
React 18바로가기
Vue 3바로가기
jQuery바로가기
Angular바로가기
Vanilla JS바로가기

🔗 링크

단위 테스트 354개 ALL PASS · MIT 라이선스

공유하기