엘릭서로 뛰어들기 전에, 좀 더 자세히 알아봅시다. 언어에 대해 아는 것은 그것이 어디에서 왔고 무엇을 할 수 있는지에 대하여 더 나은 생각을 갖게 주도록 하여 좋습니다.
저는 언어를 배우기 전에, 장단점을 배우는 것 뿐만 아니라 그것으로 무엇을 할 수 있는지 읽는 것을 좋아합니다. 그것은 저에게 그 언어가 어디에 그리고 언제 써야 하는지 도와줍니다.
엘릭서는 파이썬과 자바스크립트같이 동적 타이핑 언어입니다. 이것은 데이터 타입이 컴파일 타임이 아니라 런타임에 결정된다는 것을 뜻합니다. 한 변수는 어떤 지점에서는 문자열을 참조할 수 있고, 그 후에는 정수를 참조할 수 있습니다. 이것은 컴파일 타임에 엄격하게 알아야하 는 정적 타입 언어인 자바와 C#같은 언어와는 대조적입니다. 정적 타입 언어에서 변수는 항상 같은 타입이어야만 하고 다른 타입을 가질 수 없습니다.
이런 트레이드오프는 유연성과 이른 에러 감지의 사이에 있습니다. 정적 타입 언어는 컴파일 타임에 타입 관련된 에러를 잡을 수 있고 해당 타입 정보로 효율적인 코드 컴파일을 할 수 있지만, 코드의 유연성은 더 떨어집니다.
엘릭서는 함수형입니다. 함수형 언어는 일급 시민 함수로 되어있고 선언형 프로그래밍인 경향이 있는데, 어떻게 할 것인지 보다 무엇을 할 것인지에 초점을 맞춰야 하는 경향이 있다. 함수는 작고 단순한 경향이 있으며, 작은 함수들을 조립해서 더 큰 함수를 만듭니다. 또한 함수형 언어는 불변형 데이터를 사용하는 경향이 있습니다. 이 시점에서 저는 함수형 언어의 전문가는 아니지만, 향후 글에서 함수형 프로그래밍의 이해한 내용을 계속해서 살펴보겠습니다. 이것은 명령형 프로그래밍과는 다른 사고방식을 가져야 하고, 제가 아직 완전히 익히지 못한 부분입니다. 연습하고 함수형 예제 코드를 찾는 것은 아마 더 잘하기 위한 열쇠일 것입니다.
엘릭서 언어는 확장과 유지 보수가 가능한 애플리케이션을 만드는 것을 지향합니다. 엘릭서는 매우 이 원칙들을 강조합니다. 그리고 저는 언어를 배우면서 이러한 언어의 측면을 더 잘 이해하기를 바랍니다.
엘릭서에게는 언어 그 이상의 훨씬 더 많은 것이 있기 때문에 제가 "엘릭서 언어"라는 용어를 사용했습니다. 그것에는 실행되는 플랫폼과 주변 생태계가 있습니다. 자바, 스칼라, 클로저가 JVM 바이트 코드로 컴파일하여 자바 가상 머신(VM)에서 실행되고, C#, VB.NET, F#이 IL(중간 어셈블리) 바이트 코드로 컴파일되고 .NET언어를 위한 VM인 공용 언어 런타임에서 실행되는 것처럼, 엘릭서도 또한 바이트 코드로 컴파일되며 가상 머신에서 실행됩니다.
엘릭서가 실행되는 가상 머신은 엘릭서를 위해 만들어진 가상 머신이 아니고, 얼랭VM(혹은 BEAM)이라고 불리는 이미 존재하는 가상 머신 입니다. 이것의 공식적인 이름은 BEAM이지만, 이것이 얼랭VM으로 더 자주 불리는 것을 보았기 때문에 저는 여기서 그렇게 부르도록 하겠습니다. 얼랭은 확장 가능하고 동시에 실행할 수 있으며 견고한 코드가 가능한 플랫폼에서 실행되는 오래된(1980년대 중반부터 시작된) 언어입니다. 그래서 엘릭서는 모든 것을 새롭게 만드는 대신, 기존에 존재하는 플랫폼에 통합하였습니다.
제가 아직 엘릭서를 배우지 않았음에도, 왜 사람들이 엘릭서를 그렇게나 좋아하는지 알아보았을 때, 엘릭서가 어떻게 동시성, 확장성 그리고 견고함을 갖는지 알게 되었습니다.
무엇보다 엘릭서의 함수형 특징과 불변 데이터는 수많은 동시성 문제를 피하는 것을 의미합니다. 가변, 공유 상태 그리고 사이드 이펙트는 진심으로 멀티 스레드 프로그래밍에서 골칫거리입니다. 이것은 그 자체로 큰 주제이며 저는 아마도 이것에 대해 자세하게 파지 않을 것입니다. 함수형 프로그래밍에 대한 이 기사는 이 주제에 대해 다루고 있으므로, 더 배우고 싶으시다면 읽어보십시오.
제가 이전 글에서 설명했듯이, 엘릭서는 액터 모델의 구현을 통해 확장 가능한 동시성을 달성합니다. 엘릭서의 액터는 매우 가벼운 프로세스(운영체제의 프로세스가 아닌 가상 머신의 가상 프로세스)로 매우 적은 메모리를 사용합니다. 수십만 개 혹은 심지어 수백만 개의 이들이 얼랭VM에서 실행될 수 있어서, 많은 부하에서도 애플리케이션과 서비스가 계속 작동할 수 있습니다. 또한 이 모든 프로세스는 서로 독립적으로 실행되므로, 매우 높은 수준의 동시성을 가집니다.
프로세스 간의 통신은 불변 데이터를 포함하는 메세지를 통해 이루어집니다. 이것은 가변 데이터, 공유 상태, 잠금, 경쟁 상태 그리고 다른 언어에서 동시성 프로그래밍을 할 때 겪는 모든 문제에 대해 걱정하지 않도록 해줍니다.
엘릭서는 동일한 머신 뿐만 아니라 여러 머신에서 동시성 처리를 쉽게 할 수 있도록 하여 분산 시스템을 쉽게 만들 수 있습니다. 엘릭서 프로세스는 동일한 머신에서처럼 쉽게 다른 머신에서 돌아가는 엘릭서 프로세스에 메세지를 보낼 수 있습니다. 제가 알기로는 두 대의 머신에서 수백 대의 머신으로 확장하는 것은 비교적 간단합니다(진심으로 믿기 위해 이것을 보고 싶긴 하지만).
견고함은 슈퍼바이저라고 불리는 것에 의해 갖출 수 있습니다. 저는 이 부분에서 매우 조금밖에 알지 못하지만, 엘릭서에 대해 읽어본 것에 따르면, 이것들은 엘릭서 프로세스들을 모니터링하고 그들이 충돌 시 재시작을 할 수 있습니다. 사실 이것은 엘릭서 프로세스들을 매우 견고하게 해줍니다. 제가 이해한 바로는 프로세스들은 때때로 오류가 발생하면 의도적으로 스스로 충돌이 나도록 하고, 그것들이 되살아날 것이라고 알고 있습니다. 죽지 않는 것은 몇 가지 흥미로운 결과를 초래할 수 있습니다. 여러분은 다시 살아나리라는 것을 안다면 죽는 것을 덜 두려워할 것입니다. 저는 엘릭서의 이러한 측면을 배우는 것에 대해 정말 알고 싶지만, 이것은 제가 훨씬 나중에 배울 심화 기능이라고 생각합니다. 저희는 기초들을 먼저 숙달해야 합니다.
동시성 프로그래밍을 쉽게 만들 수 있는 엘릭서의 능력은 현재 환경에서 매우 큰 장점입니다. 프로세서의 성능은 점진적으로 향상되고 있지만, 코어 수는 점점 증가하고 가격은 내려가며 멀티 프로세서를 가진 클라우드 컴퓨팅은 더 저렴해지고 있으므로, 병렬 처리를 효율적으로 사용할 수 있는 사람은 그렇지 못한 사람보다 큰 이점을 얻게 될 것입니다.
엘릭서의 데이터는 불변입니다. 이것은 절대 변할 수 없다는 뜻입니다. 데이터가 한번 생성되면 그것은 변하지 않습니다(가비지 컬렉터가 뜰 때까지). 여러분은 절대로 그 데이터를 변경할 수 없습니다. 변수는 재할당(엘릭서 용어로는 리바운드)될 수 있지만, 데이터 자체는 변경되지 않습니다.
저는 여러분이 변하지 않을 코드에 상수 데이터로 처리했다고 생각합니다만, 가변 데이터 구조 또한 사용할 수 있습니다. 여러분은 불변 데이터로 어떻게 무엇이든 처리할 수 있는지 궁금할 것입니다. 데이터는 상태와 시간 경과에 따른 상태 변화를 나타내는 데 사용됩니다.
엘릭서는 원래 데이터 구조에서 변경 사항을 추가하여 새로운 데이터 구조를 만드는 것으로 데이터를 "수정"할 수 있습니다. 원래 데이터 구조는 변하지 않고 원래 데이터를 참조하는 것들은 여전히 그것을 참조하지만, 이제 새로운 불변의 데이터 구조를 갖게 됩니다. 엘릭서는 데이터를 그 자리에서 변경하지 않고 새로운 데이터 집합으로 변환하는 개념을 수용합니다.
이것은 이상하고 비효율적으로 들립니다. 실제로 이것은 비효율적이지 않으며 서로 다른 스레드 간에 변경할 수 있는 상태를 공유할 때 발생할 수 있는 온갖 위험한 문제들을 피할 수 있습니다. 사실 불변 데이터를 가지면 다른 영역에서 효율을 올릴 수 있습니다. 여러분은 다른 것들로 데이터가 수정되는 것을 걱정하지 않고 데이터를 공유할 수 있고, 데이터가 절대로 변하지 않는다는 것을 아는 것만으로도 가변 데이터로는 결코 달성할 수 없는 최적화를 할 수 있습니다.
엘릭서와 기반이 되는 얼랭 플랫폼은 동시성과 확장성을 전문적으로 다루며, 불변 데이터는 이를 달성하는 데 큰 도움이 됩니다. 엘릭서는 작은 부분에서의 비효율과 스레드와 프로세서 그리고 머신으로 확장되는 전체 시스템의 효율을 얻기 위해 트레이드 오프할 것입니다. 우리는 다음 장에서 불변 데이터에 대해 상세하게 다룰 것입니다.
요즘에 사용되는 많은 언어처럼, 엘릭서도 가비지 컬렉션이 있는 언어입니다. 이것은 제가 C와 C++로 개발했을 때처럼 메모리를 수동으로 할당하거나 해제할 필요가 없다는 것을 뜻합니다. 그것은 큰 고통이 될 수 있습니다. 종종 이상하고 설명할 수 없는 결함을 통해 불분명하게 나타난 문제들로 불가피하게 메모리를 추적하는 것은 큰 고통이 될 수 있습니다. 저는 더 이상 그 부류의 버그를 잡지 않아도 되기 때문에 안도감을 느끼고 있습니다. 여러분은 가비지 컬렉터가 있는 언어에서 더 이상 필요하지 않은 데이터에 대한 참조를 유지하는 것과 같이 어리석은 일을 할 수 있지만, 그것은 메모리 관리와 관련된 결함을 추적하는 것만큼 짜증 나진 않습니다.
데이터 구조를 위해 직접 메모리를 할당하고 해제하는 것 대신에 언어에서 런타임에 자동으로 할당합니다. 여러분이 그것에 대해 전혀 걱정하지 않아도 됩니다. 또한 어떤 데이터가 사용되고 어떤 데이터가 코드에서 더 이상 참조되지 않는지 감지합니다. 가비지 컬렉터는 가끔 동작하는데, 실행을 멈추고 필요하지 않은 데이터를 정리하여 힙 메모리를 해제합니다. 운영 체제 수준이나 사이클이 중요한 코드에서 이런 종류의 행동을 원하지 않겠지만, 개발의 대부분은 이것이 중요하지 않은 높은 수준에서 일어납니다.
만약 여러분이 짧은 시간 내에 여러분의 코드에서 많은 양의 데이터(혹은 수백만 개의 작은 데이터)를 만드는 많은 데이터 할당을 했다면, 가비지 컬렉션은 눈에 띄지 않는 일시 중지에서 심각하고 명백한 일시 중지로 전환될 수 있습니다. 그래서 가비지 컬렉션이 있는 환경에서의 프로그래머들은 가비지 컬렉터에게 부하를 주는 코드를 피할 수 있도록 가비지 컬렉션의 동작에 대해 알아야 햘 필요가 있습니다.
엘릭서는 동시성과 확장성을 위해 코드가 (가상) 프로세스 간에 분산되는 경향이 있어 이점을 가지고 있습니다. 각 프로세스는 자신만의 힙을 가지고 있습니다. 결과적으로 가비지 컬렉터는 전체 시스템을 한 번에 처리하는 것이 아닌 각 프로세스에 개별적으로 처리할 수 있습니다. 이것은 가비지 컬렉터가 한 번에 더 작은 양을 청소하고, 훨씬 더 적게 일시 정지합니다. 만약 하나의 가상 프로세스가 미친 듯이 메모리를 할당하고 해제한다면, 가비지 컬렉션은 시스템의 나머지 부분이 아니라 특정 프로세스에만 영향을 줄 것입니다. 엘릭서는 전체 시스템을 확장 가능하고 안정적으로 유지하도록 또다시 최적화합니다.
소프트웨어 개발에서 트레이드 오프가 없다는 것은 매우 드문 일입니다. 당연히 엘릭서도 약간의 트레이드 오프가 있습니다. 어떤 것들은 적절하고 어떤 것들은 그렇지 않습니다. 저는 이미 얼렉서가 잘하는 것에 대해 많아 알아봤습니다. 그럼 엘릭서를 사용할 때 어떤 것을 포기해야 할지 알아봅시다.
엘릭서가 불변 데이터 구조를 가진 함수형 언어라는 사실은 C나 C++ 그리고 러스트와 같은 언어들이 가지는 CPU 효율성을 가지고 있지 않다는 것을 뜻합니다. VM에서 실행되어 컴퓨팅 효율성이 떨어지고, 불변 데이터 구조는 가변 데이터 구조보다 효율적일 수 없습니다. 그래서 저는 엘릭서로 그래픽 엔진이나 운영체제를 구현하는 것을 추천하지 않습니다. 그것은 충분히 하드웨어에 가깝지 않습니다. 그래서 3D 그래픽으로 된 게임 클라이언트는 엘릭서로 구현되어서는 안 됩니다. 그러나 네트워크 게임 서버를 구현하는 것과 특히 많은 커넥션을 핸들링하는 경우는 엘릭서의 훌륭한 사용 사례가 될 것입니다.
엘릭서는 또한 수학적 연산에 최적화되어있지 않기 때문에 프로세스에 부하를 주는 연산을 위해 사용하는 것은 좋은 방법이 아닙니다. CPU를 많이 사용하는 연산이 포함된 애플리케이션에서 엘릭서를 사용할 수 없다는 아니지만, CPU에 높은 부하를 주는 부분이 있는 시스템은 아마도 그 작업에 더 적합한 언어로 구현되어야 할 것입니다. 일반적인 네트워크 애플리케이션이나 서비스 수행의 평균적인 연산은 엘릭서에서는 문제가 되지 않을 것입니다. 하지만 기가바이트의 데이터에 대한 통계 분석이나 연산이 집약된 물리 시뮬레이션 동작은 아마도 원치 않을 것입니다.
엘릭서는 컴파일 타임보다 런타임에 더 결정되는 동적 타입 언어이고, 그에 따른 모든 트레이드오프를 가집니다. 더 많은 유연성을 얻게 되지만, 코드 실행 전에 감지되는 에러는 더 적습니다. 정적 타입 언어는 컴파일 타임에 더 많은 문제를 발견할 수 있습니다.
웹 세계에서 사용되는 대부분 언어들(특히 동적 언어)은 비슷한 장단점을 가지며 CPU와 메모리에 효율적인 언어들은 웹 개발이나 동시성 프로그래밍에서 사용하는 것은 재미있지 않습니다. 엘릭서는 이 점에선 별로 특별하지 않습니다.
작은 규모에서는 엘릭서의 성능상 이점이 명확하지 않습니다. 엘릭서와 얼랭 플랫폼은 얼랭 VM에서 돌아가는 모든 프로세스에서 예측할 수 있고 성능을 위해 최적화되어있습니다. 특정 프로세스의 처리량만 최대로 올리지 않습니다. 이것은 마이크로초마다 몇 개의 커넥션을 가질 때 엘릭서의 성능은 놀랍지 않을 것이라는 뜻입니다. 5만 개의 커넥션을 가지고도 시스템이 여전히 안정적이고 반응을 할 때 성능상의 이점은 꽤 놀라울 것입니다. 엘릭서는 작은 규모에서 추가적인 비효율성을 갖더라도 시스템 레벨에선 동시성과 확장성에 최적화 되어있습니다. 즉, 엘릭서는 작은 효율성보다 큰 효율성을 중요하게 생각합니다.
또다른 단점은 엘릭서는 꽤 최신언어이고 아직 자바스트립트, 루비, C#, 파이썬 혹은 자바와 같은 언어 처럼 인기를 얻지 못했다는 점입니다. 이것은 생태계가 개발될 시간이 많지 않았고, Node.js나 루비 생태계에서 찾을 수 있었던 패캐지들이 없다는 것을 뜻합니다. 여러분은 많은 것들을 위한 패키지를 찾을 수 있지만, 모든 것을 위한 패키지는 찾을 수 없을 것입니다.
엘릭서는 모든 것을 위한 패키지나 라이브러리가 없으므로, 여러분은 가끔 얼랭 세계에 이미 존재하는 고급 기능을 위해 얼랭 라이브러리를 써야 할 수도 있고, 그렇게 되면 얼랭 라이브러리 사용을 위해 적어도 얼랭을 배워야 합니다. 또한 엘릭서나 얼랭 라이브러리가 없는 경우 직접 엘릭서 라이브러리를 작성해야 할 수도 있습니다.
저는 생태계가 더 성숙해지고, 기여자들이 많아지고, 패키지들이 생겨나고 엘릭서가 얼랭 라이브러리를 대체하면서 시간이 흐르면 생태계의 단점은 점점 사라질 것으로 생각하지만, 머지않아 Node.js나 루비 생태계를 따라잡을 것이라고 기대하지는 않습니다.
엘릭서는 조세 발림에 의해 만들어졌으며 2011년에 처음 릴리즈 된, 대부분의 현재 사용되는 언어보다 최근에 만들어졌습니다. 조세는 루비 커뮤니티에서 매우 활동적이고 잘 알려져 있었으며 레일즈 프레임워크의 코어 메인테이너였습니다. 그는 루비가 동시성 문제를 해결하는 데 최적의 언어가 아니라는 것을 깨달았고 더 나은 언어를 찾기 시작했습니다.
조세는 프로그래밍 언어 얼랭과 그것과 관련된 얼랭 가상머신과 OTP 플랫폼을 발견했습니다. 그는 그것이 동시성 문제를 얼마나 잘 해결하는 것에 대해 인상 깊게 생각했지만, 다른 언어에서 보았던 현대적인 도구들, 문서화, 언어 구조에 대해 그리워했습니다. 그는 얼랭 가상머신에서 실행되어 얼랭/OTP 플랫폼의 모든 기능을 활용할 수 있는 향상된 언어와 툴셋을 만들기 시작했습니다. 그 언어가 엘릭서 입니다. 얼랭 플랫폼의 장점을 모두 활용할 수 있는 얼랭보다 훨씬 향상된 대안이 되도록 의도하였습니다.
"거인의 어깨에 기대는 것"은 좋은 움직임이었습니다. 엘릭서는 기존 얼랭 플랫폼과 생태계에서 엄청난 힘을 얻을 수 있었으며, 만약 조세가 처음부터 다시 구현하기로 했다면 얻지 못하였을 것입니다.
조세 발림이 루비 커뮤니티에서 매우 활동적이었기 때문에, 엘릭서는 루비에서 많은 아이디어와 문법을 받아들였습니다. 적어도 저는 그렇게 들었습니다. 저는 루비를 전혀 모르기 때문에, 개인적으로 그 유사성에 대해 언급할 수 없을 것입니다. 저는 언젠가 제가 루비를 배우고 엘릭서로부터 알게 된 아이디어와 문법을 알아볼 날을 상상합니다.
비록 엘릭서가 자바스크립트, 파이썬, 루비와 같은 더 인기 있는 언어보다 사용량이 적지만, 지난 몇 년 동안 인기가 빠르게 증가하고 있습니다. 주요 장점은 확장성과 내결함성입니다. 엘릭서를 사용하는 개발자들은 다양한 배경으로부터 왔지만, 저는 루비 개발자가 엘릭서로 이동하는 것이 인기가 있을 것 같은 인상을 받았습니다. 그것은 아마도 조세 발림이 루비 커뮤니티에서 좋은 평가를 받아왔고 루비로부터 많은 아이디어와 구문을 이어왔기 때문일 것입니다.
엘릭서는 확장성 있고 강력하며 동시성 시스템을 만드는 데 주로 사용되는 것 같으며, 그중 많은 것이 웹서비스와 웹 애플리케이션입니다. 피닉스 프레임워크는 개발자들이 이러한 서비스와 애플리케이션을 만들 수 있도록 도와줍니다. 저도 피닉스를 잘 배워볼 계획이지만, 그것은 제가 엘릭서와 친해지고 난 한참 뒤일 것입니다.
엘릭서에는 다양한 도구들로 구성된 생태계가 있습니다. 여기에는 패키지 매니저와 패키지 레포지토리가 포함됩니다. 저는 얼마나 많은 패키지를 이용할 수 있는지 말할 정도로 이 생태계에 친숙하진 않지만, 아마도 npm보다는 작다고 말해되 괜찮을 것 같습니다.:)
제가 엘릭서에 대해 읽으면서 알게 된 것은, 기존 시스템의 확장성과 내결함성을 높이기 위해 보통 엘릭서로 마이그레이션 한다는 것입니다. 저는 엘릭서로 유지보수성을 높인다는 주장도 보았으나, 그것에 대해서는 제가 잘 알지 못합니다.
그러나 엘릭서로 마이그레이션 하기 전에, 조직에서는 엘릭서에 익숙한 개발자를 확보하거나 기존 인원을 엘릭서에 익숙해지도록 교육해야 합니다. 보통 둘 다 해야 합니다. 비록 엘릭서의 인기가 꾸준히 오르고 있지만, C#, 자바, 파이썬, 루비 그리고 자바스크립트와 같이 인기 있는 언어에는 아직 포함되지 않았습니다. 따라서 이미 엘릭서를 아는 개발자를 찾는 데 노력이 필요할 수 있습니다.
대부분의 엘릭서 개발자는 엘릭서가 꽤 최근 언어이기 때문에 최근에 배웠을 것이며, 그들은 엘릭서를 가르치기보다는 배우는 것을 주도했을 것입니다. 비록 엘릭서에 대한 약간의 지식과 배우려는 동기가 있는 사람이라도 엘릭서 시스템을 구현하는 데 귀중한 자원이 될 수 있습니다.
엘릭서 채택의 조직적, 기술적 관점과 성공으로 성과를 낸 기업의 몇 가지 이야기들이 Adopting Elixir라는 책에 기록되어 있습니다. 저는 현재 엘릭서가 무엇인지 더 잘 알기 위해 이 책을 읽고 있으며, 그것은 꽤 통찰력 있는 것 같습니다.
엘릭서의 엄청난 특징 중 하나는 문서입니다. 엘릭서 문서는 매우 훌륭하며, 그것을 읽는 데 문제가 없습니다. 튜토리얼보다 특정 기능에 대해 자세히 알고 싶을 때 레퍼런스로 더 유용하다고 생각합니다. 그 문서는 매우 명확하고 이해하기 쉽습니다. 이것은 제가 본 언어의 문서 중에서 다양한 수준에 맞게 잘 작성된 문서 중 하나입니다. 그리고 그 메인테이너는 추천됩니다. 문서화에 투입된 노력에 감사드립니다.
여러분은 그 문서를 엘릭서 웹사이트에서 만나볼 수 있습니다.
엘릭서가 가진 몇 가지 좋은 도구들에 대해 알고 있습니다. 패키지 매니저, 유닛 테스트 프레임워크, 빌드 도구 그리고 인터렉티브 쉘을 제공하여 빌드와 실행 프로세스를 거치지 않고도 엘릭서 코드를 가지고 놀 수 있습니다. 저는 아직 이 도구들에 대해 조금밖에 모르지만, 결국 그것들에 대해 더 많이 알게 되리라 생각합니다.