Ruby OOP에서 Elixir Functional로 예시를 통해

발행: (2025년 12월 2일 오후 01:00 GMT+9)
4 min read
원문: Dev.to

Source: Dev.to

Ruby 구현

함수형 프로그래밍을 배우는 가장 효과적인 방법 중 하나는 OOP 언어로 작성한 동일한 기능을 함수형 스타일로 변환하는 것입니다. 아래는 Ruby로 구현한 간단한 ToyRobot 객체이며, 세 가지 속성(x, y, direction)과 동작(move, turn left, turn right)을 가지고 있습니다.

class ToyRobot
  attr_reader :x, :y, :direction
  DIRECTIONS = [:north, :east, :south, :west]
  BOUNDS = {x: 0..10, y: 0..10}

  def initialize
    @x = 0
    @y = 0
    @direction = :north
  end

  def place(x, y, direction)
    if DIRECTIONS.include?(direction)
      @x = x
      @y = y
      @direction = direction
    else
      raise "Invalid direction"
    end
  end

  def report
    {x: @x, y: @y, direction: @direction}
  end

  def move
    case @direction
    when :north then @y += 1
    when :east  then @x += 1
    when :south then @y -= 1
    when :west  then @x -= 1
    end

    if @x > BOUNDS[:x].max || @y > BOUNDS[:y].max
      raise "Out of bounds"
    end
  end

  def right
    case @direction
    when :north then @direction = :east
    when :east  then @direction = :south
    when :south then @direction = :west
    when :west  then @direction = :north
    end
  end

  def left
    # implement left
  end
end

Elixir 구현

아래는 Elixir로 표현한 동일한 로봇입니다. Elixir가 처음이라면 코드를 보기 전에 직접 구현해 보세요.

defmodule ToyRobot do
  @directions [:north, :east, :south, :west]
  @bounds_x 0..20
  @bounds_y 0..20

  defstruct x: 0, y: 0, direction: :east

  def new() do
    {:ok, robot} = place(0, 0, :east)
    robot
  end

  def place(_x, _y, direction) when direction not in @directions do
    {:error, :invalid_direction}
  end

  def place(x, y, _direction) when x not in @bounds_x or y not in @bounds_y do
    {:error, :out_of_bounds}
  end

  def place(x, y, direction) do
    {:ok, %ToyRobot{x: x, y: y, direction: direction}}
  end

  def report(%ToyRobot{x: x, y: y, direction: direction}) do
    {x, y, direction}
  end

  def right(%ToyRobot{direction: direction} = robot) do
    new_direction =
      case direction do
        :north -> :east
        :east  -> :south
        :south -> :west
        :west  -> :north
      end

    %ToyRobot{robot | direction: new_direction}
  end

  def left(%ToyRobot{direction: direction} = robot) do
    # implement right
  end

  def move(%ToyRobot{x: x, y: y, direction: direction} = robot) do
    {new_x, new_y} =
      case direction do
        :north -> {x, y - 1}
        :east  -> {x + 1, y}
        :south -> {x, y + 1}
        :west  -> {x - 1, y}
      end

    if new_x in @bounds_x and new_y in @bounds_y do
      %ToyRobot{robot | x: new_x, y: new_y}
    else
      robot
    end
  end
end

핵심 차이점

메서드 vs 함수

  • Ruby (OOP): 메서드는 클래스에 속하며 객체의 내부 상태를 조작합니다.
robot = ToyRobot.new
robot.move
robot.left
  • Elixir (Functional): 모듈은 함수를 그룹화하며, 데이터를 명시적으로 전달합니다.
robot = ToyRobot.new()
ToyRobot.move(robot)
ToyRobot.left(robot)

Elixir에서는 필요한 모든 데이터를 인자로 전달해야 하지만, Ruby 메서드는 객체의 상태에 암묵적으로 접근할 수 있습니다.

가변 vs 불변

  • Ruby: 메서드는 객체의 상태를 변경합니다.
robot = ToyRobot.new
robot.move   # @x, @y change
robot.report # => {x: 0, y: 1, direction: :north}
  • Elixir: 데이터 구조는 불변이며, 함수는 새로운 구조체를 반환합니다.
robot = ToyRobot.new()
# => %ToyRobot{x: 0, y: 0, direction: :east}

new_robot = ToyRobot.move(robot)
# => %ToyRobot{x: 1, y: 0, direction: :east}

robot
# => %ToyRobot{x: 0, y: 0, direction: :east}  # unchanged

Elixir의 파이프 연산자(|>)는 변환을 연쇄적으로 연결하는 것을 간결하게 만들어 줍니다:

robot = ToyRobot.new()
|> ToyRobot.move()
|> ToyRobot.move()
|> ToyRobot.right()
|> ToyRobot.left()

결론

근본적인 차이는 상태를 다루는 방식에 있습니다:

  • Ruby (OOP) – “객체가 자신의 상태를 변경한다.”
  • Elixir (Functional) – “함수가 데이터를 받아 새로운 데이터를 반환한다.”
Back to Blog

관련 글

더 보기 »

Clprolf를 사용한 클래스 책임 분리

개요: 깨끗하고 잘 구조화된 클래스를 설계하는 것은 객체 지향 프로그래밍에서 핵심 과제입니다. Clprolf는 declensions를 도입합니다 – 간단한 방법으로 ...

함수형 쿼드트리

번역할 텍스트를 제공해 주시겠어요? URL만으로는 내용을 확인할 수 없습니다. 텍스트를 복사해서 알려주시면 한국어로 번역해 드리겠습니다.

Java OOPS 개념

Forem 로고https://media2.dev.to/dynamic/image/width=65,height=,fit=scale-down,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%...