디버깅
스크립팅에서는 오류가 없는 기능이 없습니다. 가장 신뢰할 수 있는 명령이라도 예상치 못한 입력이나 조건이 발생하면 실패할 수 있습니다. 이를 방지하기 위해 맞춤형 디버깅 시스템을 구현하고 방어 프로그래밍 기술을 채택할 수 있습니다. 오류 처리 메커니즘으로 표준 기능을 래핑하고 유익한 피드백을 제공함으로써 스크립트를 더욱 강력하고 문제 해결하기 쉽게 만들 수 있습니다.
이 전략의 핵심 부분은 전역 디버그 플래그를 사용하여 자세한 출력을 제어함으로써 정상적인 실행 중에 출력을 깨끗하게 유지하면서 필요할 때 자세한 디버깅 정보를 활성화할 수 있도록 하는 것입니다.
전역 디버그 플래그
전역 디버그 플래그는 스크립트 실행 중 정보 출력 수준을 제어하는 간단하면서도 효과적인 방법입니다. 활성화되면 문제를 추적하는 데 매우 유용한 자세한 디버깅 메시지를 제공합니다. 비활성화되면 프로덕션 용도로 출력을 간결하게 유지합니다.
;; 목적: 디버그 출력을 제어하는 전역 플래그.
(define debug #f)기본적으로 디버깅은 꺼져 있습니다. 개발 중에 자세한 출력을 활성화하려면 플래그를 #t으로 설정하기만 하면 됩니다.
;; 목적: 디버그 출력을 제어하는 전역 플래그.
(define debug #t)도우미 함수를 사용하여 특정 코드 섹션에 대한 디버깅을 일시적으로 활성화하거나 비활성화할 수도 있습니다.
로컬 디버그 제어
보다 세부적인 제어를 위해 도우미 함수를 사용하여 스크립트의 특정 부분 내에서 디버깅을 켜거나 끌 수 있습니다.
;; 목적: 코드 구간의 디버그 모드 끄기.
(define (debug-off)
(set! debug #f))
;; 목적: 코드 구간의 디버그 모드 켜기.
(define (debug-on)
(set! debug #t))이를 통해 디버깅을 동적으로 제어할 수 있습니다.
(debug-on) ;; 상세 출력 활성화
;; 여기에 스크립트 로직
(debug-off) ;; 상세 출력 비활성화디버그 메시징 시스템
Scheme에서 디버그 출력을 효율적으로 처리하기 위해 여러 도우미 기능이 포함된 구조화된 접근 방식을 사용합니다. 이러한 기능을 사용하면 디버그 및 경고 메시지가 명확하고, 읽기 쉽고, 유지 관리 가능합니다.
디버그 메시징 시스템 개요
디버그 메시징 시스템은 다음 구성 요소로 구성됩니다.
debug-message– 디버깅이 활성화되면 디버그 메시지를 표시합니다.serialize-item– 다양한 Scheme 데이터 유형을 문자열 표현으로 변환합니다.concat– 여러 항목을 단일 문자열로 연결합니다.list->string– 목록을 읽을 수 있는 문자열로 형식화합니다.message– Lumi의 메시지 콘솔에 출력을 표시합니다.warning-message– 경고가 활성화되면 경고 메시지를 표시합니다.
각 기능은 구조화된 메시지의 형식을 지정하고 표시하는 역할을 합니다.
디버그 메시지 기능
debug-message 함수는 디버그 출력을 표시하는 핵심 방법입니다. 디버깅이 활성화된 경우에만 메시지가 표시되도록 합니다.
;; 목적: 디버그 메시지 표시.
(define (debug-message . items)
(when debug (message "> " (apply concat items))))when debug조건은 디버깅이 활성화된 경우에만 메시지가 표시되도록 보장합니다.- 명확성을 위해 메시지 앞에
"> "이 붙습니다. - 이 함수는
concat을 사용하여 메시지 내용의 형식을 지정합니다. - 마지막으로
message을 호출하여 출력을 Lumi의 메시지 콘솔로 보냅니다.
사용 예:
;; 목적: 항목의 트리 위치를 반환하거나, 항목이 유효하지 않으면 #f 반환
(define (get-item-tree-position image item)
(if (item-is-valid? item)
(let ((position (list->item (lumi-image-get-item-position image item))))
(debug-message "item : " (item-get-name item) " has tree position : " position)
position)
#f))디버깅이 활성화되면 출력은 다음과 같을 수 있습니다.
> item: background-layer has tree position : 3디버그 메시지용 데이터 직렬화
메시지에는 목록, 벡터, 숫자 등 다양한 데이터 유형이 포함될 수 있습니다. 형식이 올바른지 확인하기 위해 serialize-item을 사용합니다.
;; 목적: 다양한 Scheme 데이터 유형(리스트, 벡터, 페어 등)을 변환
;; 문자열 표현으로 변환.
(define (serialize-item item)
(cond
((and (list? item) (null? item)) "\"\"") ; 빈 목록
((and (string? item) (string=? item "")) "\"\"") ; 빈 문자열
((list? item) (list->string item)) ; 중첩된 목록
((vector? item) ; 벡터 처리
(string-append "#("
(string-join (map serialize-item (vector->list item)) " ")
")"))
((pair? item) ; 쌍 처리
(string-append "("
(serialize-item (car item))
" . "
(serialize-item (cdr item))
")"))
((number? item) (number->string item)) ; 숫자
((symbol? item) (symbol->string item)) ; 심볼
((boolean? item) (if item "#t" "#f")) ; 부울값
((string? item) item) ; 문자열
(else (warning-message "serialize-item: Unsupported item type!" item))))사용 예:
(serialize-item '(1 2 3))출력:
list:
1
2
3메시지 연결
여러 메시지 구성 요소를 단일 문자열로 병합하려면 concat을 사용합니다.
;; 목적: 여러 항목을 하나의 문자열로 연결.
(define (concat . items)
(apply string-append (map serialize-item items)))사용 예:
(concat "Image size: " 1920 "x" 1080)목록을 문자열로 형식화하기
list->string 함수는 목록을 형식이 지정된 문자열로 변환합니다.
;; 목적: 항목 목록을 읽기 쉬운 문자열로 변환.
(define (list->string list)
(if (list? list)
(string-append "list: \n" (string-join (map serialize-item list) "\n"))
(warning-message "list->string: Input is not a list!")))경고 메시지
warning-message 함수는 debug-message과 유사하게 작동하지만 디버깅이 비활성화된 경우에도 경고를 표시합니다.
;; 목적: 경고 메시지 표시.
(define (warning-message . items)
(if warning
(message "Warning: " (apply concat items)))
#f)- 경고가 활성화된 경우에만 메시지가 표시되도록 합니다(
warning플래그는common.scm에#t으로 설정됨). concat을 호출하여 메시지 내용의 형식을 지정합니다.message을 사용하여 Lumi에 출력을 보냅니다.
표준 기능 강화
디버깅 시스템이 구축되면 자세한 메시지를 통합하여 기능 라이브러리를 향상시킬 수 있습니다. 이를 통해 항목 상태, 변수 값 및 함수 호출에 대한 통찰력을 얻을 수 있습니다.
일반적인 예는 item-is-valid?입니다. 이는 lumi-item-id-is-valid을 래핑하여 #t 또는 #f을 반환합니다. #f이 반환되면 호출 코드에서 warning-message을 트리거할 수 있습니다. 입력이 숫자가 아닌 경우 함수에서 경고를 표시할 수 있습니다.
;; 목적: 항목이 유효한지 확인하고 #t 또는 #f 반환.
;; 항목이 숫자가 아니면 경고를 표시.
(define (item-is-valid? item)
(if (number? item)
(= (list->item (lumi-item-id-is-valid item)) 1)
(begin
(warning-message "item-is-valid?: Expected a number, but received: " item)
#f)))실제 사용법
Scheme 플러그인을 개발할 때 이러한 방식으로 함수를 래핑하면 디버깅 시간이 크게 줄어들고 강력하고 유지 관리 가능한 코드가 보장됩니다. 디버깅 시스템을 갖추고 있으면 스위치를 한 번만 누르면 오류 콘솔에서 구조화된 디버그 스트림을 생성할 수 있습니다.
이 디버그 스트림에서 함수 호출은 별표(*)로 표시되어 특히 복잡한 플러그인에서 스크립트 실행을 추적하고 오류를 찾아내기가 더 쉽습니다. 이러한 가시성은 작업 흐름을 이해하고 예상치 못한 동작을 효율적으로 진단하는 데 도움이 됩니다.
*을 사용하기 위한 메시지 기능의 래퍼
(define (call . items)
(when debug (message "* (" (apply concat items) ")")))실제로 사용되는 call의 예:
;; 목적: 주어진 그룹 마스크 목록에 텍스처링 프로세스 적용
(define (process-masks groups pattern) (call 'process-masks)
(for-each
(lambda (group)
(let ((mask (add-mask-to-layer group ADD-MASK-WHITE)))
(message "Process mask : " (item-get-name group))
(fill-and-adjust-group-mask group mask pattern)
(lumi-layer-set-opacity group (get 'color-opacity))
(lumi-item-set-expanded (item-get-parent group) 0)
(lumi-selection-none (get-image))))
(ensure-list groups)))플러그인이 실행되는 디버그 스트림의 예:
> Recording the plug-in settings
* (convert-gui-settings)
> all-masks : 1
> strokes : 1
> color : 1
> plate-layer : 1
> drawables : #(37)
* (filter-list-for-matching-groups)
> all-masks : #t
> sub-groups of group : root
blue
blue_strokes
blue_colour
yellow
yellow_strokes
yellow_colour
gray
gray_strokes
gray_colour
> groups with identifier in name: _colour
blue_colour
yellow_colour
gray_colour
* (filter-list-for-matching-groups)
> all-masks : #t
> sub-groups of group : root
blue
blue_strokes
blue_colour
yellow
yellow_strokes
yellow_colour
gray
gray_strokes
gray_colour
> groups with identifier in name: _strokes
blue_strokes
yellow_strokes
gray_strokes
* (begin-apply-texture)
Start Apply Texture
> color : #t
Texturing color group masks
> color-pattern : 2655
* (process-masks)
Process mask : blue_colour
* (fill-and-adjust-group-mask)
> Fill-and-adjust : blue_colour mask
> using pattern for fill : 2655
* (apply-color-effect)
> color-contrast : 64
> color-levels-gamma : 10
> levels on drawable: blue_colour mask
> gamma: 8.2
> low-in: 0.7278 high-in: 0.9222
> low-out: 0 high-out: 1
> light-opacity : 6
> light-opacity : 6
* (apply-light-effect)
> apply-light-effect opacity : 6
> from layer : light_blue
> edit-copy light_blue
> edit-paste blue_colour mask
> shade-opacity : 60
> shade-opacity : 60
* (apply-light-effect)
> apply-light-effect opacity : 60
> from layer : shad_blue_opa*5
> edit-copy shad_blue_opa*5
> edit-paste blue_colour mask
* (apply-opaque-effect)
> children in : blue_colour
blue_colour
hue_blue
light_blue
shad_blue_opa*5
base_blue
...
...
...
Finished Apply Texture!이 구조화된 로그는 함수 호출 및 데이터 변경에 대한 명확한 타임라인을 제공하므로 디버깅 및 성능 분석이 훨씬 쉬워집니다.
결론
구조화된 디버깅 시스템을 구현함으로써 실행에 대한 실시간 통찰력을 제공하는 보다 안전하고 유지 관리가 용이한 스크립트를 만듭니다.
주요 내용
- 자세한 내용 제어 – 전역 디버그 플래그를 사용하여 출력 레벨을 관리합니다.
- 명확한 피드백 제공 – 유용한 디버그 메시지로 표준 기능을 래핑합니다.
- 강건성 향상 – 예상치 못한 입력을 적절하게 처리하여 오류를 방지합니다.
- 문제 해결 단순화 – 구조화된 디버그 메시지를 사용하면 문제를 더 쉽게 진단하고 해결할 수 있습니다.
이러한 접근 방식을 사용하면 스크립트가 데이터를 처리할 때 효과적으로 “자기 설명"하여 좌절감을 줄이고 작업 흐름 효율성을 향상시킵니다. 디버깅은 사후 대응적인 일이 아닌 사전 예방적인 도구가 되어 스크립팅 프로세스를 더욱 원활하고 보람되게 만듭니다.