From 9874b9fec36bcb076aa3073f2a35760556cacbcf Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 2 Aug 2026 21:01:20 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Bolt:=20CSS=20=EB=AC=B8=EC=9E=90?= =?UTF-8?q?=EC=97=B4=20=EB=B0=8F=20SHA-256=20=ED=95=B4=EC=8B=9C=20?= =?UTF-8?q?=EC=97=B0=EC=82=B0=EC=9D=84=20=EC=B5=9C=EC=83=81=EC=9C=84=20?= =?UTF-8?q?=EC=86=8D=EC=84=B1=EC=9C=BC=EB=A1=9C=20=EC=B6=94=EC=B6=9C?= =?UTF-8?q?=ED=95=98=EC=97=AC=20=EC=84=B1=EB=8A=A5=20=EC=B5=9C=EC=A0=81?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `process_dir` 내에 위치하여 디렉토리마다 불필요하게 반복 재할당 및 계산되던 `cssContent`, `styleHash` (비용이 큰 SHA-256 계산), `css` 변수를 파일 최상위 레벨로 이동 - 이를 통해 애플리케이션 시작 시 한 번만 계산되도록 하여 O(N) 오버헤드를 O(1)로 제거 - 암시적 getter에 대한 100% JaCoCo 테스트 커버리지를 유지하기 위해 `MainTest.kt`에 `testCssPropertiesCoverage` 테스트 추가 - `.jules/bolt.md`에 성능 개선 사항 기록 및 영문 항목 한국어 번역 완료 --- .jules/bolt.md | 17 ++++++++--------- src/main/kotlin/html4tree/main.kt | 16 +++++++++------- src/test/kotlin/html4tree/MainTest.kt | 7 +++++++ 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 19b4c61..8929384 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -27,19 +27,18 @@ **학습:** 디렉토리 목록(`list()` 또는 `listFiles()`)을 단순히 필터링하여 `Set`에 추가하는 경우처럼 특정 순서가 필요하지 않은 작업에서 `.sorted()`를 호출하면 불필요한 O(N log N) 오버헤드가 발생합니다. **조치:** `Set`과 같은 순서에 무관한 자료구조에 요소를 추가하기 위한 필터링 작업에서는 디렉토리 목록에서 `.sorted()` 호출을 제거하여 성능을 최적화합니다. -## 2024-05-18 - [디렉토리 목록 캐싱을 통한 I/O 오버헤드 최적화] -**Learning:** `process_dir` 및 `process_ignore_file`과 같은 함수에서 동일한 디렉토리에 대해 `listFiles()` 또는 `list()`를 반복적으로 호출하면, 파일 시스템 I/O로 인한 불필요한 성능 저하가 발생합니다. -**Action:** 디렉토리를 순회할 때 상위 루프에서 `listFiles()`를 한 번만 호출하여 캐싱한 후, 결과를 인자로 전달(예: `dirFiles` 배열)하여 중복된 파일 시스템 호출을 제거해야 합니다. +## 2024-05-18 - 디렉토리 목록 캐싱을 통한 I/O 오버헤드 최적화 +**학습:** `process_dir` 및 `process_ignore_file`과 같은 함수에서 동일한 디렉토리에 대해 `listFiles()` 또는 `list()`를 반복적으로 호출하면, 파일 시스템 I/O로 인한 불필요한 성능 저하가 발생합니다. +**조치:** 디렉토리를 순회할 때 상위 루프에서 `listFiles()`를 한 번만 호출하여 캐싱한 후, 결과를 인자로 전달(예: `dirFiles` 배열)하여 중복된 파일 시스템 호출을 제거해야 합니다. ## 2024-08-01 - URL 인코딩 빌더 지연 생성 **학습:** URL 인코딩이 필요 없는 안전한 경로 문자열에서도 항상 `StringBuilder`를 생성하면 hot path에서 불필요한 할당이 발생합니다. **조치:** 예약 바이트를 처음 만났을 때만 `StringBuilder`를 만들고, 그 전까지는 원본 문자열을 그대로 반환하는 지연 생성 패턴을 사용합니다. -## $(date +%Y-%m-%d) - Optimize OS stat calls in file listing -**Learning:** Replaced three separate OS stat calls (`Files.isDirectory(it.toPath(), LinkOption.NOFOLLOW_LINKS)`, `!it.isDirectory()`, and `!Files.isSymbolicLink(it.toPath())`) with a single `Files.readAttributes` call. The original code caused significant I/O overhead. This reduces file metadata fetching time significantly. -**Action:** Always consider using `Files.readAttributes` to fetch multiple file attributes at once rather than calling separate boolean checks like `isDirectory` or `isSymbolicLink` on individual files when iterating directories. -## 2025-01-24 - 단일 readAttributes 호출로 파일 속성 조회 최적화 -**학습:** `isDirectory`, `!it.isDirectory()`, `isSymbolicLink` 3개의 개별적인 파일 시스템 I/O 호출을 수행하면 성능 저하가 큽니다. 이를 단일 `Files.readAttributes` 호출로 변경하여 메타데이터를 한 번에 조회함으로써 I/O 오버헤드를 대폭 줄일 수 있음을 확인했습니다. -**조치:** 디렉토리 순회 시 파일의 여러 속성을 확인할 때는 개별적인 stat 호출보다 `Files.readAttributes`를 사용하여 필요한 모든 속성을 한 번에 가져오는 방식을 우선적으로 고려해야 합니다. + ## 2025-01-24 - 단일 readAttributes 호출로 파일 속성 조회 최적화 **학습:** `isDirectory`, `!it.isDirectory()`, `isSymbolicLink` 3개의 개별적인 파일 시스템 I/O 호출을 수행하면 성능 저하가 큽니다. 이를 단일 `Files.readAttributes` 호출로 변경하여 메타데이터를 한 번에 조회함으로써 I/O 오버헤드를 대폭 줄일 수 있음을 확인했습니다. **조치:** 디렉토리 순회 시 파일의 여러 속성을 확인할 때는 개별적인 stat 호출보다 `Files.readAttributes`를 사용하여 필요한 모든 속성을 한 번에 가져오는 방식을 우선적으로 고려해야 합니다. + +## 2025-01-25 - 정적 속성을 파일 레벨로 추출하여 재계산 오버헤드 방지 +**학습:** 재귀적인 파일 시스템 탐색에서 `process_dir` 내부에 위치한 고정 문자열(CSS)이나 비용이 큰 연산(SHA-256 해시)은 디렉토리마다 불필요하게 반복 계산되어 성능 저하를 초래합니다. +**조치:** 이들을 Kotlin 파일의 최상위 레벨 속성(Top-level properties)으로 이동시켜 애플리케이션 시작 시 한 번만 계산되도록 최적화합니다. 이때 JaCoCo 커버리지 100%를 유지하기 위해 암시적 getter에 대한 명시적인 테스트를 추가해야 합니다. diff --git a/src/main/kotlin/html4tree/main.kt b/src/main/kotlin/html4tree/main.kt index b455862..87b28a0 100644 --- a/src/main/kotlin/html4tree/main.kt +++ b/src/main/kotlin/html4tree/main.kt @@ -240,11 +240,9 @@ fun write_index_file(curr_dir: File, content: String) { } } -fun process_dir(curr_dir: File, excludeSet: Set? = null, dirFiles: Array? = null){ - - val exclude: Set = excludeSet ?: process_ignore_file(curr_dir) - - val cssContent = """ +// ⚡ Bolt Performance Optimization: Move static CSS and expensive SHA-256 hash computation +// to top-level properties to compute them exactly once, rather than per directory. +val cssContent = """ body { font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; line-height: 1.5; @@ -310,13 +308,17 @@ fun process_dir(curr_dir: File, excludeSet: Set? = null, dirFiles: Array } """ - val styleHash = "sha256-" + Base64.getEncoder().encodeToString(MessageDigest.getInstance("SHA-256").digest(cssContent.toByteArray(Charsets.UTF_8))) +val styleHash = "sha256-" + Base64.getEncoder().encodeToString(MessageDigest.getInstance("SHA-256").digest(cssContent.toByteArray(Charsets.UTF_8))) - val css = """ +val css = """ """ +fun process_dir(curr_dir: File, excludeSet: Set? = null, dirFiles: Array? = null){ + + val exclude: Set = excludeSet ?: process_ignore_file(curr_dir) + val index_top = """ diff --git a/src/test/kotlin/html4tree/MainTest.kt b/src/test/kotlin/html4tree/MainTest.kt index 1349471..d820a8d 100644 --- a/src/test/kotlin/html4tree/MainTest.kt +++ b/src/test/kotlin/html4tree/MainTest.kt @@ -676,6 +676,13 @@ class MainTest { assertFalse(excluded.contains("test.txt1001")) } + @Test + fun testCssPropertiesCoverage() { + assertTrue(cssContent.contains("font-family")) + assertTrue(styleHash.startsWith("sha256-")) + assertTrue(css.contains("