Elixir
함수형 동시성 프로그래밍 언어
함수형 동시성 프로그래밍 언어
Elixir는 2011년 Jose Valim이 Ruby on Rails 코어 팀에서 활동하면서 만든 함수형 프로그래밍 언어입니다. Erlang VM(BEAM) 위에서 실행되어 통신, 금융, IoT 등 고가용성이 필요한 분야에서 수십 년간 검증된 안정성을 그대로 활용할 수 있습니다.
Elixir의 핵심 철학은 '확장성과 유지보수성'입니다. 불변 데이터와 순수 함수를 기반으로 하며, 액터 모델을 통해 수백만 개의 경량 프로세스를 동시에 실행할 수 있습니다. 이로 인해 WhatsApp은 2백만 동시 접속을 단일 서버에서 처리할 수 있었습니다.
Phoenix 프레임워크는 Elixir의 킬러 앱으로, 실시간 웹 애플리케이션 개발에 특화되어 있습니다. LiveView를 사용하면 JavaScript 없이도 서버 사이드 렌더링으로 실시간 UI를 구현할 수 있어, 프론트엔드 복잡성을 크게 줄여줍니다.
실무에서 Elixir는 Discord(동시 접속 처리), Pinterest(API 서버), PepsiCo(IoT 플랫폼) 등에서 사용됩니다. 패턴 매칭, 파이프 연산자(|>), OTP(Open Telecom Platform) supervision tree 등의 기능으로 장애 복구가 자동화되어 "let it crash" 철학을 실현합니다.
# 1. 기본 문법과 패턴 매칭
defmodule Calculator do
# 패턴 매칭으로 함수 오버로딩
def add(a, b) when is_number(a) and is_number(b), do: a + b
def add(a, b) when is_list(a) and is_list(b), do: a ++ b
def add(_, _), do: {:error, "지원하지 않는 타입"}
end
# 파이프 연산자로 데이터 변환 체이닝
result = [1, 2, 3, 4, 5]
|> Enum.filter(&rem(&1, 2) == 0) # 짝수 필터: [2, 4]
|> Enum.map(&(&1 * &1)) # 제곱: [4, 16]
|> Enum.sum() # 합계: 20
IO.puts("짝수 제곱의 합: #{result}")
# 2. 동시성 - GenServer 프로세스
defmodule Counter do
use GenServer
# 클라이언트 API
def start_link(initial \\ 0), do: GenServer.start_link(__MODULE__, initial)
def increment(pid), do: GenServer.call(pid, :increment)
def get(pid), do: GenServer.call(pid, :get)
# 서버 콜백
@impl true
def init(count), do: {:ok, count}
@impl true
def handle_call(:increment, _from, count), do: {:reply, count + 1, count + 1}
def handle_call(:get, _from, count), do: {:reply, count, count}
end
# 3. Phoenix LiveView 예시 (실시간 웹)
defmodule MyAppWeb.CounterLive do
use Phoenix.LiveView
def mount(_params, _session, socket) do
{:ok, assign(socket, count: 0)}
end
def handle_event("increment", _, socket) do
{:noreply, update(socket, :count, &(&1 + 1))}
end
def render(assigns) do
~H"""
<button phx-click="increment">
클릭 수: <%= @count %>
</button>
"""
end
end
"실시간 알림 시스템은 Elixir Phoenix로 구현하면 좋겠습니다. LiveView로 WebSocket 관리 없이 실시간 UI를 만들 수 있고, BEAM VM 덕분에 수십만 동시 연결도 안정적으로 처리할 수 있어요."
"Elixir의 장점은 OTP supervision tree를 통한 장애 격리입니다. 프로세스가 크래시하면 supervisor가 자동으로 재시작하기 때문에, 하나의 버그가 전체 시스템에 영향을 주지 않습니다. 이것이 'let it crash' 철학의 핵심입니다."
"여기서 if-else 대신 패턴 매칭을 사용하면 더 명확해질 것 같아요. case 문으로 각 상태를 명시적으로 처리하면 컴파일러가 누락된 케이스도 경고해줍니다."
Elixir의 = 은 패턴 매칭 연산자입니다. `x = 1` 후 `1 = x`는 성공하지만, `2 = x`는 MatchError를 발생시킵니다. 변수 재바인딩을 원하면 ^ 핀 연산자를 활용하세요.
리스트나 맵을 "수정"하면 항상 새 데이터가 반환됩니다. `list = [1, 2] |> List.insert_at(0, 0)`처럼 결과를 새 변수에 바인딩해야 합니다.
`String.upcase(String.trim(" hello "))` 대신 `" hello " |> String.trim() |> String.upcase()`로 작성하면 데이터 흐름을 왼쪽에서 오른쪽으로 읽을 수 있어 가독성이 높아집니다.