Elixir 1.19
(elixir-lang.org)- Elixir 1.19 버전은 타입 시스템 강화와 컴파일 성능 개선을 통해, 더 많은 버그를 빠르게 탐지할 수 있게 됨
- 타입 추론이 익명 함수와 프로토콜까지 확장되어, 사용자의 타입 주석 없이도 더욱 폭넓은 자동 검증이 가능해짐
- 대형 프로젝트에서 최대 4배까지 향상된 컴파일 속도를 제공하며, 병렬 컴파일과 코드 로딩 최적화가 포함됨
- Erlang/OTP 28 지원, OpenChain 인증 도입 등 생태계와 공급망 투명성도 강화됨
- 그 외에도 옵션 파싱 개선, ExUnit 디버그성 향상, shell 기반 문서 접근성 개선 등 여러 기능이 포함됨
Elixir 1.19 주요 개선 사항
타입 시스템 개선
모든 구성요소의 타입 추론
- Type inference(타입 추론)은 표현식의 타입을 컴파일 시점에 자동 판정하는 기능임
- 기존에는 패턴, 가드, 반환값 위주로 타입 추론을 지원하려 했으나, 이번 릴리즈에서 모든 구성요소(가드를 제외)의 타입 추론을 도입함
- 모듈 내 및 Elixir 표준 라이브러리 함수 호출 등도 참고하여 타입을 추론하므로, 예전에는
dynamic() -> boolean()으로 추론되던 함수도integer() -> boolean()처럼 더 명확하게 추론 가능해짐 - 타입 추론은 컴파일 속도, 표현력, 점진적 컴파일, 에러 명확성 등 여러 트레이드오프를 수반하므로, 추후에는 가드 타입 추론 및 종속성 타입 정보도 포함할 예정임
- 함수에 타입 시그니처가 명시되면, 타입 추론이 아닌 명시 타입 검사로 동작하여, 사용자 주석에 맞는 타입만 허용함
프로토콜 디스패치 및 구현 시 타입 검사
- Elixir는 이제 프로토콜 호출 및 구현 시 타입 검사를 적용함
- 예를 들어,
String.Chars프로토콜을 구현하지 않은 타입을 문자열 보간에 전달하면 경고 메시지를 출력함 - for comprehension에서
Enumerable프로토콜을 만족하지 않는 타입을 제너레이터로 전달 시에도 경고가 발생함 - 이러한 타입 검사로 컴파일 타임에 더 많은 버그를 방지할 수 있음
익명 함수의 타입 추론과 검사
- Elixir 1.19는 익명 함수에 대한 타입 추론 및 타입 검사를 지원함
- 예로,
%{}타입을 기대하는 익명 함수에"hello"와 같이 잘못된 타입을 전달하는 경우 컴파일 타임 경고로 바로 감지할 수 있음 - 함수 캡처(
&String.to_integer/1등)에도 타입 추론이 적용되어 자동화된 타입 검증 범위가 확대됨
참고 및 파트너
- 해당 타입 시스템은 CNRS와 Remote의 파트너십으로 개발되었음
- Fresha, *Starfish* *, Dashbit 등이 후원함
대형 프로젝트에서의 빠른 컴파일 속도
코드 로딩 병목 개선
- 기존에는 모듈 정의 즉시 로딩하였으나, 이번 릴리즈에서는 지연 로딩(lazy loading) 전략으로 변경함
- 이로 인해 코드 서버 부담이 줄고 병렬 컴파일 성능이 향상되어, 대형 프로젝트 컴파일 속도가 2배 이상 증가함
- 두 가지 주요 주의사항
- 컴파일 중 별도의 프로세스를 생성하여 동일 프로젝트 내 모듈에 접근 시 로딩이 누락될 수 있으니, 이를 우회하는 방법으로
Kernel.ParallelCompiler.pmap/2혹은Code.ensure_compiled!/1등을 사용함 -
@on_load콜백 내에서 동일 프로젝트 내 모듈 호출 시 에러 발생 가능성 있음, 필요 시@compile {:autoload, true}옵션을 활용함
- 컴파일 중 별도의 프로세스를 생성하여 동일 프로젝트 내 모듈에 접근 시 로딩이 누락될 수 있으니, 이를 우회하는 방법으로
- 두 경우 모두 과거에는 비결정적 컴파일 에러가 발생할 수 있었으나, 이번 개선으로 결정적(재현성 있는) 컴파일 환경을 보장함
의존성 병렬 컴파일
- 환경 변수
MIX_OS_DEPS_COMPILE_PARTITION_COUNT를 활용하여, 의존성(dependency) 병렬 컴파일을 지원함 - 여러 OS 프로세스를 동시에 활용해 의존성을 병렬로 컴파일하므로, 프로젝트 규모 및 CPU 코어 수에 따라 컴파일 성능이 최대 4배까지 개선됨
- 실험적으로 전체 코어의 절반 정도 값을 설정하는 것이 리소스 활용에 효과적임
- 병렬화로 인해 메모리 사용량이 증가할 수 있으므로 CI나 빌드 서버 적용 시 주의 필요함
Erlang/OTP 28 지원
- Elixir 1.19는 Erlang/OTP 28.1+ 버전을 공식 지원함
- Erlang/OTP 28에서의 정규표현식 표현 변경에 따라, struct의 기본값으로 정규표현식 사용은 불가능해짐
- struct 초기화 시에는 여전히 정규표현식을 사용 가능함
OpenChain 인증 도입
- 이번 릴리즈는 OpenChain 규격 준수를 시작하는 첫 버전임
- 각 릴리즈에는 CycloneDX 1.6/SPDX 2.3 포맷의 SBoM(Source Bill of Materials) 이 포함됨
- 이는 릴리즈 구성요소 및 라이선스의 공급망 투명성을 높이고, 더 엄격한 관리에 기여함
- 해당 작업은 Jonatan Männchen이 진행하였으며, Erlang Ecosystem Foundation이 후원함
기타 개선 사항
- 옵션 파싱, ExUnit의 디버그 및 성능, shell 기반 문서 접근성 등 다양한 도구 및 라이브러리 개선 사항이 추가됨
- 보다 상세한 릴리즈 노트는 CHANGELOG를 참고함
Hacker News 의견
-
Elixir에 자동 타입 체크 기능을 점진적으로 도입하는 방식이 다른 프로그래밍 언어들도 참고할 만한 훌륭한 언어 개선 사례임을 강조함, 기존에 큰 변화로 인해 생태계가 둘로 쪼개진 언어 사례가 많았으며, Elixir는 2018년부터 언어 자체가 완성되었다고 José가 명확히 밝혀 안심인 상황임, 언어와 코어는 더 이상 깨지지 않아서 안정감이 크다는 점을 설명함, 관련 발표 영상을 추천함, 일관성 있고 훌륭한 운영에 감명을 받음
- 주요 언어에서 큰 변화로 인한 생태계 분열 사례는 파이썬3와 펄6 정도만 생각남, 이 둘의 변화가 워낙 충격이 컸기 때문에 다른 언어 변화도 거대하게 느껴지는 것 같음
- Elixir에선 항상 버전 업그레이드에 쫓기지 않고, 도입되는 변화들을 확인하면서 쓸만한 새 기능 때문에 업그레이드를 하고 싶어지는 경험임, 강제로 끌려가듯 버전을 바꾸라고 할 때처럼 불안하거나 스트레스 받지 않음
- 2017년부터 프로덕션 환경에서 Elixir를 써왔는데, 매번 업그레이드할 때마다 기대했던 것보다 훨씬 원활히 진행되었음, 오히려 Erlang/OTP 업그레이드 때가 호환성 문제로 더 복잡했던 적이 많은데, 그래서 대부분 최신 Elixir를 쓰면서도 OTP 버전은 한두 달 더 기다려 충돌 요소가 처리된 뒤에 업그레이드함
- Elixir는 여전히 다소 미흡하고 편의성도 부족해 목표 달성을 위한 확실한 가이드와 생태계의 안정화가 필요함, 많은 패키지가 방치되거나 문서가 미흡해 Phoenix 생태계 변화 속도를 따라가기 어렵다고 느낌, LiveViews나 특정 컴포넌트 시스템을 원하지 않는 사용자도 많고, 타 도구 및 기술과의 호환성 진입장벽이 높음, 파이썬3는 2에서 3로의 전환이 반드시 필요했고 자동화된 마이그레이션 도구로 비교적 잘 해냈으나 시행착오도 많았음, 반면 Ruby 3는 외부 타입파일 도입과 툴 분열이 오히려 혼란을 초래했고, 보일러플레이트와 거버넌스 문제, gem 탈취 등 부정적인 경험이 얽혀 있어 Ruby를 잘 쓰지 않게 되었음, 훌륭한 언어라도 미숙한 운영이 모든 것을 망칠 수 있으니 성숙한 협력과 소통, 좋은 변화 관리가 중요함을 강조함, 언어 디자인 변화는 충분한 사전 실험과 신중함, 그리고 사용자에게 미리 충분히 안내하여 불필요한 혼란을 최소화해야 한다고 생각함, 앞으로 Elixir/Phoenix/OTP가 더 쉽고 강력하며 생산적이고 성능도 뛰어나 다양한 유저들이 안심하고 쓸 수 있게 되길 희망함, Livebook과 Exercism Elixir 트랙 같은 리소스를 추천함
-
Elixir는 꾸준히 훌륭한 기능과 개선사항을 내놓으며 안정적으로 발전 중임, 언어 구조가 탁월하고 창시자들이 지속적으로 올바른 방향성을 잡고 있어 정말 인상적임, 오히려 일상적으로 Elixir를 쓸 기회가 없는 점이 아쉬움
- Elixir를 쓰고 싶어서 회사까지 그만두고 직접 창업했음
-
Phoenix의 의존성 컴파일 속도 관련 실험 데이터 공유함, Mac M1 Max에서 기본 Phoenix 의존성만 포함된 작은 앱 기준,
MIX_OS_DEPS_COMPILE_PARTITION_COUNT환경변수값에 따라 다음과 같은 컴파일 시간이 측정됨PARTITION_COUNT=1: 12.336초 (유저 32.30s, 시스템 7.23s, CPU 320%) PARTITION_COUNT=5: 6.970초 (유저 0.37s, 시스템 0.49s, CPU 12%) PARTITION_COUNT=10: 7.236초 (유저 0.38s, 시스템 0.50s, CPU 12%)중간마다
rm -rf _build명령으로 캐시 삭제함- 이후 실행들은 캐시가 적용된 상태로 측정된 것으로 보이며, 아마 dep 폴더에서 직접 네이티브 컴파일이 이뤄져
_build에 흔적이 남지 않았을 수 있음 - 왜 이 릴리즈의 기능에 대한 벤치마크 결과가 다운보트를 받는지 이해가 안됨, 의견을 달아줄 수 있는지 궁금함
- 이후 실행들은 캐시가 적용된 상태로 측정된 것으로 보이며, 아마 dep 폴더에서 직접 네이티브 컴파일이 이뤄져
-
최근 몇 달간 Gleam을 정말 좋아하게 되었음, Elixir의 타입 시스템 도입도 반갑지만, 예전엔 이 부분이 Elixir를 채택하기 힘든 주요 요인이었음, 언젠가 Elixir에 재도전해보고 싶은데 자바스크립트의 타입스크립트처럼 외형만 타입드이고 실제로는 many lib이나 패키지에서 그냥 dynamic/any 타입이 되는 건 아닐까 걱정됨, 이런 걱정이 괜한 것일지 궁금함, Beam은 정말 훌륭함
- 타입스크립트와는 여건이 다름, 패턴 매칭 덕분에 기존 Elixir 코드베이스도 적어도 50% 정도 타입 추론이 가능할 것 같고, vanilla Elixir가 타입을 기본 제공하기에 유지보수되는 코드는 빠르게 타입화가 진행될 것으로 보임, 나는 타입 시스템을 선호하지 않고 JS만 쓰지만 Elixir는 타입 적용이 자연스럽게 이뤄짐, 타입스크립트는 위쪽으로 올라가는 반면 Elixir는 자연스럽게 아래로 전파되는 환경임
- Gleam은 OTP/BEAM의 진짜 강점을 완벽히 누릴 수 없음, Elixir만이 제공하는 매력임
- Elixir는 예전부터 primitive 타입, 구조체, shape 기반 구조 분해 등 이미 타입 개념이 존재했고, Dialyzer, TypedStruct 같은 도구로 타입 체크 가능함, 자바스크립트처럼 황당한 무타입 언어가 아님
- Gleam도 좋지만 JVM에서는 Kotlin이 Ruby와 유사한 문법의 타입 언어라서 compile-to-JS도 쓸 수 있음
-
Elixir는 웹 개발 환경 중에서 가장 유망하다고 느껴짐, 실제 현업에서 만날 때마다 Elixir를 쓰는 조직이나 팀의 수준이 일반적인 곳보다 더 높은 것 같음, 지속적 개발을 해야 하는 환경에서 Elixir가 방향성과 표준을 계속 제시해준다고 생각함
-
Elixir 릴리즈가 CycloneDX 1.6 이상, SPDX 2.3 이상의 Source SBoM 포맷 지원을 시작했다고 소개함, 언어 차원에서 SBOM 관리가 이뤄지는 점이 정말 고마운 일임, 아쉽게도 현재 회사에서 Elixir를 사용하지 않음
-
실사용 오픈소스 Elixir 프로젝트에 기여하고 싶으면, 예전 Mozilla Hubs의 주요 컴포넌트가 독립 프로젝트로 계속 Elixir로 개발 중임, Hubs Foundation/reticulum 참고 바람
-
Elixir 표준 라이브러리 기반으로 동적 타입에서 불리언, 정수에서 불리언 등 앱 특정 상황에 맞는 타입 추론이 컴파일 타임에 가능함
-
Elixir 개발 경험은 없지만 팬임, 예전엔 Ruby의 실용성과 아름다움을 좋아했으나 타입 시스템에 매력을 느끼면서 언어를 바꿈, Elixir와 Ruby 모두 타입 시스템을 도입했지만, 지금은 문법적으로 "타이핑된 Ruby" 느낌인 Kotlin을 주로 씀
- Kotlin은 거의 우리가 진짜 원했던 jruby의 느낌임
-
Soketi로 pusher sdk와 연동해 이벤트 브로드캐스트를 처리하고 있음, 앱이 실시간 엔드포인트와 rest 엔드포인트가 혼합된 구조이고 실시간 연산 부하가 크진 않지만 필요하다면 Go로 따로 처리할 생각임, 곧 협업 기능도 추가할 예정인데, 이런 상황에서 Phoenix를 도입하는 게 맞을지 고민임