Mino: Clojure 영감을 받은 인체공학을 휴대용 C99에 적용

임베디드 스크립팅 언어 세계에서 개발자들은 Lua와 같은 경량 언어와 현대 함수형 언어의 강력한 데이터 처리 인체공학 사이에서 트레이드오프를 겪는 경우가 많습니다. Mino는 휴대용 C99로 작성된 Clojure 영감을 받은 Lisp를 제공함으로써 이 격차를 메우고, 기존 호스트 애플리케이션에 최소한의 마찰로 삽입될 수 있도록 설계되었습니다.

작은 메모리 사용량에 지속 가능한 불변 데이터 구조와 능력 기반 보안 모델을 결합함으로써, Mino는 JVM이나 무거운 런타임의 오버헤드 없이 유연하고 샌드박스된 스크립팅 레이어가 필요한 개발자들에게 매력적인 대안을 제공합니다.

계층화된 임베딩 접근법

Mino는 “tiers” 개념을 중심으로 설계되어, 개발자들이 필요로 하는 메모리 사용량과 기능 사이의 정확한 균형을 선택할 수 있게 합니다. 이러한 모듈성은 언어가 “삽입하기에 충분히 작고” 동시에 “유용할 만큼 충분히 빠른” 상태를 유지하도록 보장합니다.

1. Floor (최소)

이는 런타임 중 가장 간소화된 버전으로, 리더, 평가기, 가비지 컬렉터, 지속 컬렉션, 숫자 연산, 그리고 기본 매크로와 같은 절대 필수 요소에 집중합니다. core.clj 평가는 제외되어, 약 613KB의 작은 발자국과 0.23ms의 매우 빠른 초기화 시간을 제공합니다.

2. Standard (전체 Clojure 표면)

Floor 계층을 기반으로 Standard 버전은 Clojure 스크립터가 기대하는 기능들을 추가합니다. 여기에는 정규식, 대수, 멀티메서드, 프로토콜, 트랜스듀서가 포함됩니다. 이 계층은 발자국을 약간 늘려 728KB가 되며 초기화 비용은 5.3ms입니다. 특히, 이 계층은 여전히 샌드박스로, 호스트가 명시적으로 허용하지 않는 한 I/O 기능을 제공하지 않습니다.

3. Standalone (전체 스위트)

Standalone 계층은 I/O, 파일 시스템 접근, 소프트웨어 트랜잭셔널 메모리(STM), 에이전트, 비동기 기능, 번들된 clojure.* 표준 라이브러리, 그리고 REPL을 포함한 완전한 패키지입니다. 987KB와 5.5ms의 초기화 시간으로 Clojure와 유사한 전체 환경을 제공합니다.

성능 및 이식성

Mino의 주요 강점 중 하나는 콜드 스타트 성능입니다. x86_64 Linux에서 Floor 계층의 실제 시간 콜드 스타트(50회 실행 중 중앙값)는 1.04ms입니다. 이는 Lua 5.5(0.78ms)와 동등한 수준이며 Janet(1.95ms)보다 앞서 있어, 프로세스 생성 시간이 중요한 환경에 적합합니다.

휴대용 C99로 작성되었기 때문에 Mino는 C FFI를 지원하는 거의 모든 호스트에 임베드될 수 있습니다. 여기에는 C++, Rust, Go, Java, .NET, Swift, Zig 등이 포함됩니다. 외부 런타임, JIT, 데몬이 필요 없으며, 호스트 프로세스가 실행을 완전히 제어합니다.

아키텍처 기둥

격리된 런타임 및 메모리 안전성

각 Mino 런타임은 전용 힙과 가비지 컬렉터를 가진 독립적인 실패 도메인으로 동작합니다. 공유된 가변 상태와 잠재적인 레이스 조건을 방지하기 위해 런타임 간 데이터 이동은 깊은 복사를 통해 처리됩니다. 이 아키텍처는 단일 프로세스가 완전 격리된 다수의 테넌트를 호스팅할 수 있게 합니다.

능력 기반 인터옵

보안은 런타임 설계에 내재되어 있습니다. 새 Mino 런타임은 파일 시스템 접근, 네트워크 접근, 주변 상태 등 어떠한 능력도 없이 시작합니다. 임베더는 각 능력을 명시적으로 허용하고, 스크립트가 호출할 수 있는 특정 호스트 타입과 메서드를 등록해야 합니다.

Clojure 영감을 받은 인체공학

스크립터에게 Mino는 Clojure를 강력하게 만드는 고수준 추상화를 제공합니다:

  • Persistent Immutable Data Structures: 별칭 버그와 “누가 내 테이블을 변형했는가”와 같은 놀라움을 없앱니다.
  • Lazy Sequences: 잠재적으로 무한한 데이터 스트림을 효율적으로 처리할 수 있게 합니다.
  • Tail-Call Optimization: 재귀 함수(예: drain 연산)가 일정한 스택 공간에서 실행될 수 있도록 보장합니다.
  • REPL-Driven Workflow: 호스트 애플리케이션을 다시 컴파일할 필요 없이 실시간 검사와 런타임 설정 변경을 지원합니다.

실용 구현: 세 역할 워크플로우

Mino는 세 가지 주요 역할 사이에 명확한 관심사 분리를 정의합니다:

  1. Application Developer(애플리케이션 개발자): 런타임을 임베드하고 특정 능력을 선택함으로써 보안 경계를 정의합니다.
  2. C++ Engineer(C++ 엔지니어): 호스트 타입을 스크립트에 노출합니다. 호스트 객체는 자동 GC 정리가 가능한 타입 태그가 붙은 핸들로 래핑됩니다. API가 스택 인덱스 대신 직접 값 포인터를 사용하기 때문에 전통적인 C 기반 임베딩 API에서 흔히 발생하는 오프바이원 인덱싱 오류를 제거합니다.
  3. Scripter(스크립터): Lisp 구문을 사용해 비즈니스 로직을 작성합니다. 키워드를 데이터 접근자로, 컬렉션을 호출 가능한 프레디케이트로 활용하며, 호스트 객체를 마치 네이티브 Mino 타입처럼 다룹니다.

잠재적 사용 사례

그 설계 덕분에 Mino는 특히 다음 분야에 적합합니다:

  • Rules Engines & Policy(규칙 엔진 및 정책): 선언적 비즈니스 로직을 위해 호스트 상태를 Mino 프레디케이트에 노출합니다.
  • Plugin Systems(플러그인 시스템): 엄격히 제어된 리소스 제한과 주변 접근이 없는 사용자 작성 스크립트를 로드합니다.
  • Data Pipelines(데이터 파이프라인): 구조적 공유가 가능한 지속 컬렉션 위에서 map, filter, reduce를 조합합니다.
  • Game Scripting(게임 스크립팅): 무한 루프나 크래시를 방지하기 위해 샌드박스와 단계 제한이 있는 플레이어용 프로그래머블 콘솔을 제공합니다.
  • Interactive Consoles(인터랙티브 콘솔): 실시간 디버깅 및 런타임 구성을 위한 앱 내 REPL을 임베드합니다.

Sources