ESM アジャイル事業部 開発者ブログ

永和システムマネジメント アジャイル事業部の開発者ブログです。

物理スイッチとウェブ UIを繋ぐ。Elixirで。

はじめに

近ごろ IoT プログラミングしたい欲が再起動した e.mattsan です。

IoT とは言っても Raspberry Pi などではマシンパワーも小さくなく、外部にデバイスを接続する以外は PC のプログラミングとほぼ変わりありません。

今回の記事は、題名の通り、ブラウザ上に表示したボタンでブレッドボード上の LED の点灯状態を制御し、ブレッドボード上のスイッチでブラウザ上のアイコンの表示状態の変更をすることを試みます。

Elixir とウェブアプリケーションと IoT

今回も、使う言語は Elixir です。

Elixir には Phoenix というウェブアプリケーションのフレームワークがあります。 また Phoenix ほど知られていないかもしれませんが、組み込みシステム向けの Nerves というプラットフォームも開発が進んでいます。 加えて。ハードウェア制御のための Elixir Circuits というライブラリ群も充実してきています。

www.phoenixframework.org nerves-project.org elixir-circuits.github.io

今回の記事では、一足飛びにウェブと LED を繋ぐのでなく、LED の自動点滅から始まって最終的にウェブからの制御まで進めてゆきます。 駆け足で実装してゆきますので、環境の用意など詳細は適宜ドキュメントを確認してください。

ハードウェア制御のハードルは意外に低い、ということをこの記事で実感していただけたら幸いです。

用意するもの

デバイスを制御するので、開発マシン以外にもいくつか用意が必要です。

  • 開発およびウェブアプリケーションを実行するマシン
    • ここに掲載したコードは MacBook Pro で開発し動作を確認しました
  • 組み込みシステムとして Raspberry Pi
    • 今回は Raspberry Pi Zero W を利用しています
  • Nerves アプリケーションを書き込む micro SD
    • 開発マシンから書き込めるようにアダプタ等を用意しておいてください
  • LED と物理スイッチ、電流制限や入力プルダウンのための抵抗器、およびそれらを配線するためのブレッドボードとケーブルをいくつか
  • 開発マシンと Raspberry Pi を接続する USB ケーブル
    • 通信と給電を兼ねます

準備ができたら、まずは定番の LED を点滅させるプログラムから作ってゆきます。

Nerves アプリケーションで LED を点滅させる

最初に Raspberry Pi 単体で LED を点滅させる Nerves アプリケーションを作成してみます。

開発マシン上で開発し、起動可能なバイナリを作成して microSD に書き込み、それを使って Raspberry Pi を起動するという段取りになります。

Nerves 公式のドキュメントに従って環境の用意ができたら、新しい Nerves アプリケーションのプロジェクトを作成します。

mix nerves.new led
cd led

対象となるハードウェアは環境変数で指定します。 今回は Raspberry Pi Zero W を対象にするので次のように指定しておきます。

export MIX_TARGET=rpi0

GPIO パッケージを追加する

Raspberry Pi の GPIO の制御には Elixir Circuits の GPIO パッケージを使います。

Nerves アプリケーションの mix.exs ファイルを編集して依存するパッケージの指定を追加し、mix deps.get コマンドでパッケージを取得します。

# mix.exs

  defp deps do
    [
      # ... 略
      {:circuits_gpio, "~> 2.0"}
    ]
  end

LED を点滅させる

LED を点滅させるプロセスを扱うモジュールを作成します。

このモジュールでは、 1 秒ごとに自分にメッセージを送信し、メッセージを受信するたびに状態を反転して GPIO に書き込むことで点滅を実現します。

# lib/led.ex

defmodule Led do
  use GenServer

  # プロセスを起動する関数
  def start_link(opts) do
    GenServer.start_link(__MODULE__, opts, name: __MODULE__)
  end

  # プロセスを初期化する関数
  def init(_opts) do
    {:ok, gpio17} = Circuits.GPIO.open("GPIO17", :output) # GPIO 17 を出力として利用

    tick()

    {:ok, %{gpio17: gpio17, led: 0}} # LED の初期状態として 0 = 消灯 を記憶
  end

  # 受信した :tick メッセージをハンドリングする関数
  def handle_info(:tick, state) do
    led = 1 - state.led # LED の状態を反転

    set_led(state.gpio17, led) # GPIO に値を書き込む
    tick()

    {:noreply, %{state | led: led}} # 新しい LED の状態で更新する
  end

  defp tick do
    Process.send_after(self(), :tick, 1_000) # 1,000 ミリ秒後に自分に :tick というメッセージを送る
  end

  defp set_led(gpio, value) do
    Circuits.GPIO.write(gpio, value)
  end
end

アプリケーションを起動したときに作成したモジュールのプロセスも起動するように、lib/led/application.ex を編集して起動プロセスの一覧にモジュール名を追加します。

# lib/led/application.ex

    children =
      [
        # ... 略
        Led
      ] ++ children(target())

mix firmware コマンドで実行してバイナリイメージを作成します。

バイナリができたら、開発マシンにアダプタなどで microSD を接続してアクセスできる状態になるのを待ち、 mix firmware.burn コマンドで書き込みます。 書き込みが完了すると自動的に microSD が取り出された状態になるので、microSD を Raspberry Pi に差し替えます。

開発マシンから直接 microSD へ書き込む必要があるのはこの初回のみで、次回以降は USB でアップロード可能です。

Raspberry Pi の準備ができたら、部品をブレッドボード上で繋ぎます。 次のような並びでつないでください。

GPIO 17 --- 抵抗器 --- LED --- GND

最後に開発マシンと Raspbery Pi を USB ケーブルを繋いで Raspberry Pi を起動します。 後ほど通信を行いますので、給電専用のポートに繋がないように注意してください。

少し待つと LED が 1 秒間隔で点滅し始めることが確認できると思います。

スイッチで LED を点灯消灯する

次に、LED の点灯をスイッチで制御できるようにします。 ここでは GPIO 17 ピンの隣の GPIO 27 ピンを入力として利用することにします。

先ほどのモジュールのコードを編集し、GPIO 27 を入力として設定します。 加えて GPIO 27 の入力の立ち上がりで割り込みが発生するように設定します。

割り込みは GPIO パッケージで Elixir のメッセージに変換され送信されます。 先ほどと同じように、そのメッセージをハンドリングすることで LED の状態を制御できるようになります。

# lib/led.ex

defmodule Led do
  use GenServer

  def start_link(opts) do
    GenServer.start_link(__MODULE__, opts, name: __MODULE__)
  end

  def init(_opts) do
    {:ok, gpio17} = Circuits.GPIO.open("GPIO17", :output)
    {:ok, gpio27} = Circuits.GPIO.open("GPIO27", :input) # GPIO 27 を入力として利用

    :ok = Circuits.GPIO.set_interrupts(gpio27, :rising) # 信号の立ち上がりの時に割り込みが発生するように設定する

    {:ok, %{gpio17: gpio17, gpio27: gpio27, led: 0}}
  end

  # 受信した GPIO メッセージをハンドリングする関数
  def handle_info({:circuits_gpio, _gpio_spec, _timestamp, _value}, state) do
    led = 1 - state.led

    set_led(state.gpio17, led)

    {:noreply, %{state | led: led}}
  end

  defp set_led(gpio, value) do
    Circuits.GPIO.write(gpio, value)
  end
end

mix firmware コマンドを実行してバイナリイメージを作成します。

バイナリを書き込む前に、ブレッドボード上にスイッチを用意します。 次のような並びでつないでください。

GPIO 27 ---+--- スイッチ --- 電源
           |
         抵抗器
           |
          GND

バイナリができたら、今度は直接 microSD に書き込む代わりに mix upload コマンドを実行して USB 経由でアップロードします。 アップロードが完了すると Raspberry Pi は自動的に再起動します。

起動シーケンスが終わるのを待ってスイッチを何回か押してみてください。 押すたびに点灯消灯が切り替わるのが確認できると思います。

ソフトウェアインタフェースを追加する

ウェブアプリケーションに移る前に、ソフトウェアインタフェースを用意しておきます。 点灯/消灯のための onoff 、状態を調べるための on? の 3 つです。 このインタフェースは、あとでウェブアプリケーションからも利用します。

モジュールに次のコードを追加します。

ここで cast, call という関数と handle_cast, handle_call というハンドラが出てきますが、これらもメッセージのやり取りで実現されています。 castcall で LED を制御するプロセスにメッセージを送り、ハンドラで受信したメッセージを処理します。 cast の場合は一方通行ですが call の場合は値を返すことができます。

# lib/led.ex

  def on do
    GenServer.cast(__MODULE__, :on)
  end

  def off do
    GenServer.cast(__MODULE__, :off)
  end

  def on? do
    GenServer.call(__MODULE__, :on?)
  end
# lib/led.ex

  def handle_cast(:on, state) do
    set_led(state.gpio17, 1)
    {:noreply, %{state | led: 1}}
  end

  def handle_cast(:off, state) do
    set_led(state.gpio17, 0)
    {:noreply, %{state | led: 0}}
  end

  def handle_call(:on?, _from, state) do
    {:reply, state.led == 1, state}
  end

もう一度バイナリを作成しアップロードします。 Raspberry Pi が再起動したら、USB で SSH 接続を試します。 開発マシンから次のように入力してください。

$ ssh nerves.local # Nerves アプリケーション標準のホスト名

接続できたら Nerves プロジェクトのロゴとプロンプトが表示されると思います。 プロンプトが表示されたら次のように関数を入力して実行してみてください。 Led.on で点灯、Led.off で消灯、Led.on? で状態の確認ができると思います。

iex(1)> Led.on
:ok
iex(2)> Led.off
:ok
iex(3)> Led.on?
false
iex(4)> Led.on
:ok
iex(5)> Led.on?
true

SSH 接続から抜けるには exit 関数を実行します。

iex(6)> exit

ウェブアプリケーションを作る

ウェブアプリケーションには Phoenix フレームワークを利用しますが、さらにブラウザ・サーバ間で双方向の通信を実現したいので LiveView という仕組みを利用します。

開発マシンで、Nerves アプリケーションのディレクトリとは別に、新しい Phoenix アプリケーションのプロジェクトを作成します。

mix phx.new web_ui --no-ecto # データベースを使用しないオプションを指定
cd web_ui

プロジェクトができたら、LiveView のモジュールの新しいファイル lib/web_ui_web/live/led_live.ex を追加します。

# lib/web_ui_web/live/led_live.ex

defmodule WebUiWeb.LedLive do
  use WebUiWeb, :live_view

  def mount(_params, _session, socket) do
    {:ok, assign(socket, led: 0)}
  end

  def render(assigns) do
    ~H"""
    <.button phx-click="on">ON</.button>
    <.button phx-click="off">OFF</.button>
    <.icon :if={@led != 1} name="hero-light-bulb" class="bg-gray-500" />
    <.icon :if={@led == 1} name="hero-light-bulb-solid" class="bg-blue-500" />
    """
  end

  def handle_event("on", _params, socket) do
    {:noreply, assign(socket, led: 1)}
  end

  def handle_event("off", _params, socket) do
    {:noreply, assign(socket, led: 0)}
  end
end

次に、作成した LiveView を利用するようにルーティングを変更します。 lib/web_ui_web/router.ex を編集し、get "/", PageController, :home となっている行を live "/", LedLive に書き換えます。

# lib/web_ui_web/router.ex

   scope "/", WebUiWeb do
     pipe_through :browser
 
-    get "/", PageController, :home
+    live "/", LedLive
   end

ここまでできたらサーバを起動します。

mix phx.server

サーバが起動したら https://localhost:4000 にアクセスしてみてください。 ON と OFF の 2 つのボタンととアイコンが 1 つ表示され、ボタンを押すとアイコンの状態が変化することが確認できると思います。

今はブラウザ上の表示だけの制御ですが、これをこの後ブレッドボード上の LED と連動させてゆきます。

ノードを接続する

連動のために、開発マシン上で実行されている Phoenix アプリケーションと Raspberry Pi 上で実行されている Nerves アプリケーションを接続することを考えます。

今回は Elixir のノードを接続する仕組みを利用します。 ノードとはここではそれぞれのアプリケーションのことと思っていてください。 同一マシン上で起動した複数のノードも、ネットワークで繋がった異なるマシンで起動したノードも、この仕組みで接続することが可能です。

Nerves アプリケーション側のノードを設定する

異なるマシンの間でノードを接続するには、ホストの名前を含んだノード名と、共通で利用するクッキーを設定しておく必要があります。

そのためにプロセスの初期化のコードに次の 3 行を追加します。

# lib/led.ex

  def init(_opts) do
    # ... 略

    # 次の 3 行を追加
    {_, 0} = System.cmd("epmd", ["-daemon"])
    {:ok, _} = Node.start(:"nerves@nerves.local")
    true = Node.set_cookie(:my_secret_cookie)

    {:ok, %{gpio17: gpio17, gpio27: gpio27, led: 0}}
  end

追加したら mix firmware & mix upload でアップロードします。

接続を確かめる

Raspberry Pi が再起動するのを待って、開発マシン側で Elixir のインタラクティブシェルを起動します。 Nerves アプリケーションと同じように、ここでもノード名とクッキーを設定します。

iex --name me@0.0.0.0 --cookie my_secret_cookie

プロンプトが表示されたら次のように関数を実行してください。 うまく接続できていれば LED が点灯するはずです。

GenServer.cast({Led, :"nerves@nerves.local"}, :on)

これはノードの名前を指定している以外は先ほど Nerves アプリケーションに追加した関数と同じ内容であることがわかると思います。 ノードを接続しても開発マシン側から Nerves アプリケーションで定義された関数が見えるわけではないので、内部の実装をそのまま使って実行しています。

接続できていれば GenServer.cast({Led, :"nerves@nerves.local"}, :off) で消灯したり、GenServer.call({Led, :"nerves@nerves.local"}, :on?) で状態を確認したりすることも可能です。

ウェブアプリケーションに LED のインタフェースを追加する

開発マシンから LED の点灯の制御の確認できたので、次はウェブアプリケーションからの操作を実装します。

今回は Nerves アプリケーションとウェブアプリケーションでコードを共有していないので、ウェブアプリケーションに LED 操作のための新しいモジュールを追加することにします。

ウェブアプリケーションに新しく lib/web_ui/led.ex というファイルを追加します。

# lib/web_ui/led.ex

defmodule WebUi.Led do
  def on do
    GenServer.cast({Led, :"nerves@nerves.local"}, :on)
  end

  def off do
    GenServer.cast({Led, :"nerves@nerves.local"}, :off)
  end

  def on? do
    GenServer.call({Led, :"nerves@nerves.local"}, :on?)
  end
end

LiveView のボタンイベントのハンドラでこの追加したモジュールの関数を呼び出します。

# lib/web_ui_web/live/led_live.ex

defmodule WebUiWeb.LedLive do
  use WebUiWeb, :live_view

  def mount(_params, _session, socket) do
    # 現在の LED の状態を取得して表示に反映する
    led =
      if WebUi.Led.on?() do
        1
      else
        0
      end

    {:ok, assign(socket, led: led)}
  end

  # ... 略

  def handle_event("on", _params, socket) do
    WebUi.Led.on() # 追加
    {:noreply, assign(socket, led: 1)}
  end

  def handle_event("off", _params, socket) do
    WebUi.Led.off() # 追加
    {:noreply, assign(socket, led: 0)}
  end
end

ページを再読み込みしたら ON / OFF のボタンを押してみてください。

LED の状態をウェブアプリケーションに通知する

いよいよ最後です。 LED の状態の変化をウェブアプリケーションに通知し、ブレッドボード上のスイッチ操作で点灯、消灯する LED の状態をブラウザの表示に反映させます。

通知を受けるプロセスを用意する

まず、先ほどウェブアプリケーションに追加したモジュールをプロセス化して、スイッチ操作のイベントメッセージを受信できるようにします。 表示に反映する前にログを出力することでメッセージを受信していることを確認します。

# lib/web_ui/led.ex

defmodule WebUi.Led do
  use GenServer

  require Logger # 追加

  # プロセスを起動する関数
  def start_link(opts) do
    GenServer.start_link(__MODULE__, opts, name: __MODULE__)
  end

  # ... 略

  # プロセスを初期化する関数
  def init(_opts) do
    {:ok, nil}
  end

  # スイッチ操作のイベントメッセージをハンドリングする関数
  def handle_cast(message, state) do
    Logger.debug(inspect(message)) # メッセージをログ出力する

    {:noreply, state}
  end
end

アプリケーションを起動したときにプロセスも起動するように、起動プロセスの一覧に今回作成したモジュールを追加します。

# lib/web_ui/application.ex

    children = [
      # ... 略
      WebUi.Led
    ]

Nerves アプリケーション側では LED の状態が更新されたらウェブアプリケーションへメッセージを送るようにします。

# lib/led.ex

  defp set_led(gpio, value) do
    GenServer.cast({WebUi.Led, :"me@0.0.0.0"}, {:nerves_led, value}) # 追加

    Circuits.GPIO.write(gpio, value)
  end

mix firmware & mix upload でアップロードします。

Raspberry Pi が再起動したら、ウェブアプリケーションも再起動します。 このとき、ノード名とクッキーを設定するために次のように起動してください。

elixir --name me@0.0.0.0 --cookie my_secret_cookie -S mix phx.server

ブラウザを開いて ON / OFF ボタンで操作できることが確認できたら、次はブレッドボード上のスイッチを押してみてください。 LED の状態が変化するたびにウェブアプリケーションのログにその状態が表示されることを確認できると思います。

...
[debug] {:nerves_led, 0}
[debug] {:nerves_led, 1}
...

LED の状態を表示する

ウェブアプリケーション側のプロセスでメッセージを受信できたので、今度はこのメッセージを LiveView のプロセスにブロードキャストします。 LiveView プロセスはブロードキャストされたメッセージを受けて LED の状態をブラウザの表示に反映します。

Phoenix にはこのようなときのために Phoenix.PubSub というライブラリが用意されているのでこれを利用します。

ウェブアプリケーション側の WebUi.Led モジュールに、購読を設定する subscribe 関数と、メッセージを受けた時に購読しているプロセスにブロードキャストするコードを追加します。

# lib/web_ui/led.ex

defmodule WebUi.Led do
  use GenServer

  @topic "nerves:led" # 追加

  # ... 略

  # 購読したいプロセスが呼び出す関数
  def subscribe do
    Phoenix.PubSub.subscribe(WebUi.PubSub, @topic)
  end

  # ... 略

  def handle_cast(message, state) do
    Logger.debug(inspect(message))

    # 購読しているプロセスにメッセージをブロードキャストする
    Phoenix.PubSub.broadcast(WebUi.PubSub, @topic, message)

    {:noreply, state}
  end
end

LiveView のモジュールには、購読の開始とブロードキャストされたメッセージをハンドリングするコードを追加します。

# lib/web_ui_web/live/led_live.ex

defmodule WebUiWeb.LedLive do
  use WebUiWeb, :live_view

  def mount(_params, _session, socket) do
    # 接続が確立したら購読を開始する
    if connected?(socket) do
      WebUi.Led.subscribe()
    end

    # ... 略
  end

  # ... 略

  # メッセージを受信したら表示状態を更新する
  def handle_info({:nerves_led, led}, socket) do
    {:noreply, assign(socket, led: led)}
  end
end

複数のブラウザでページを開いて、ブレッドボード上のスイッチを押したり、ブラウザ上のボタンを押したりしてみてください。 ブレッドボード上のLED とブラウザ上のアイコンの状態がすべて連動していることが確認できると思います。

考察

今回は大まかに次の図のような構成になりました。

ここで赤い線の部分が Elixir のメッセージングで通信している部分です。

  • ネットワークからのリクエスト
  • デバイスをまたいだノード間の通信
  • ハードウェアの割り込み
  • 状態通知のブロードキャスト

すべて同じメッセージングの仕組みで処理できています。

Elixir の土台である Erlang/OTP が分散コンピューティングを標榜し、元々このようなことができるように設計されているので不思議ではないのかもしれませんが。

それでも、プロセスとメッセージによるプロセス間通信という Elixir の基本的な仕組みを使って、さまざまな要素を繋ぐことができるというのは、やはり興味深いものがあります。

つい先日、Elixir の新しい書籍が出版されました。 基本的なプログラミングだけでなく Phoenix や Nerves 、今回の記事では触れなかった数値計算や機械学習についてもくわしく解説されています。

弊社とも 箱庭ラボ などを介してゆかりのある 高瀬英希 先生 が Nerves の章を執筆されています。

この記事を読んで、Elixir のことを「なんだかよくわからないけれども面白そうだ」と思われた方は、お手に取ってみるのもよいかもしれません。


また「なんだかよくわからないけれどもこんな記事を書く面白そうな人間がいるぞ」と関心を持たれた方は、こちらをのぞいてみるのもよいかもしれません。

お立ち寄り、お待ちしております。

agile.esm.co.jp

Rails / OSS パッチ会オンライン 2024年2月のお知らせ

2024年2月の Rails / OSS パッチ会を 2月28日(水)に Discord でオンライン開催します。

この会をひとことでいうと、日頃のお仕事で使っている Rails をはじめとする OSS について、upstream にパッチを送る会です。

会には Ruby と Rails のコミッターである顧問の a_matsuda もいますので、例えば Rails に送るパッチのネタがあるけれど、パッチを送るに適しているかの判断やパッチを送る流れが悩ましいときなど a_matsuda に相談して足がかりにするなどできます。

開催時間は 17:00-19:00 となりますがご都合のあう方はぜひご参加下さい。

Discord の Rails/OSS パッチ会サーバーへの招待 URL は以下です👇

discord.gg

5月に開催される RubyKaigi 2024 に向けた話題などがあるかもしれません。

弊社の構文解析器研究部に関心がある方や、これからパッチ会に参加してみたいという方、OSS 開発者間の会話に興味があるので聞いてみたいという方もお気軽にどうぞ。


永和システムマネジメントでは、Ruby とアジャイルソフトウェア開発を通じてコミュニティと成長したいエンジニアを絶賛募集しています。

agile.esm.co.jp

【レポート】中高生国際Rubyプログラミングコンテスト2023 in Mitaka 永和賞受賞者の方との交流会を開催しました

こんにちは!maimuです。

昨年12月に東京都三鷹市で中高生国際Rubyプログラミングコンテスト2023 in Mitakaが開催されました。

www.ruby-procon.net

「つくりたい!が世界を変えていく!」をテーマに中高生がプログラミングを学び、自分でコンピューターを動かしたときの感動やつくった作品を発表する経験を通して将来への夢をはぐくむことを目的に毎年実施されているイベントです。永和システムマネジメントはスポンサーとして参加し、部門賞として「永和賞」を選出しました。

blog.agile.esm.co.jp

今回のコンテストではWebアプリ・IoT部門で金光峻希さんが最優秀賞と永和賞を受賞されました。

永和賞受賞の副賞として書籍のプレゼントと金光さんを東京の弊社オフィスにお招きして交流会を開催したため、その内容をレポートとしてまとめたいと思います!

好きなRubyメソッドは?の自己紹介からワイワイ開発タイム

金光さんとの交流会は1月末に永和システムマネジメント東京支社で開催しました。

アジャイル事業部所属の

の3名が交流会の企画担当として、当日どんな風に進めていくかなどを話し合いながら準備を進めていきました。

交流会当日は以下のタイムテーブルを用意していたのですが、話が盛り上がりすぎて時間が足りなくなるほど充実した会となりました。

自己紹介ではアジャイル事業部恒例?の「好きなRubyメソッド」についてを紹介し、話が弾み始めた頃に金光さんが開発されたアプリに軸を移して技術選定についてや最新技術へのキャッチアップの仕方、Rubyについてなどプログラミングに関する話題でワイワイ会話しながら開発作業タイムを楽しみました。

金光さんの開発されたアプリ「SQSO Web」

金光さんはSQSO Webというアマチュア無線のログ(交信記録・業務日誌)を作成するための Web アプリケーションを開発されました。

アマチュア無線の部活用PC(GNU/Linux)で使えるログソフトが無かったことから、自分の状況に合ったログアプリをスマートフォンやタブレットからも利用できるようにするため自分自身でWebアプリとして開発したそうです。

Rakefile、ディレクトリ構造、サーバー起動用のシェルスクリプト、Rodauthの導入などバックエンドもこだわりが詰まったWebアプリです。

弊社アジャイル事業部では普段Ruby on Railsを利用して開発をしていますが、金光さんがご自身のアプリに利用された技術への洞察が深く「RodauthとRailsの組み合わせはどうですか?」と逆に提案をいただいて盛り上がる場面もありました。

スペシャルゲストの登場

金光さんのアプリではフレームワークとしてRodaを使用されています。

その繋がりでRodaの開発者であるJeremy Evansさんの書籍『研鑽Rubyプログラミング』を永和賞の副賞としてプレゼントすることになりました。

研鑽Rubyプログラミングは弊社フェローである角谷信太郎さんが翻訳者であることから、交流会当日角谷さんにもご参加いただけないかご相談したところ快諾いただき、スペシャルゲストとして盛り上げていただきました。

交流会を終えて

今回、オンラインではなくオフラインの場で交流会を開催したのですが、プログラミングが大好きな人達が同じ場に集まり、ワイワイすることで生まれる「場の熱量」を体感し、会に参加した永和メンバーもとても良い刺激をいただく機会になりました。

金光さんからも以下の感想をいただき、その場にいた全員が有意義な時間を過ごせたのではないかと思います。

交流会が始まるまでは緊張していましたが、皆様が温かく迎えて下さったお陰で、楽しく過ごすことができました。 バグの修正や新機能の追加についてなどアドバイスを頂き、大変勉強になりました。 また、読みたいと思っていた『研鑽Rubyプログラミング』を頂き、その上訳者の角谷様よりサインを書いていただき、とても感激しました。

金光さん自身は開発されたアプリの機能追加も検討されていて、今後の拡張がとても楽しみです。

金光さん、東京までご訪問いただきありがとうございました!


アジャイル事業部のRubyアジャイル受託開発は、アジャイル開発を10年以上続けて培った、決して手法や方法論ではまとめきれない、実践知や価値観、それを届ける人で構成されています。Ruby とアジャイルソフトウェア開発を通じてコミュニティと共感していけるお客様とエンジニアを絶賛募集しています。

agile.esm.co.jp

オンライン技術顧問サービスはじめました

永和システムマネジメント アジャイル事業部として『オンライン技術顧問サービス』をはじめました。ひとことでいうと、私 (@koic) による技術顧問サービスです。

どんなサービス?

アドバイザーという位置付けで参画する形での有料サービスです。基本的な動きとしては、まず GitHub リポジトリに招待していただくことになります。すでに本サービス相当の入り方をしている実績としては、招待していただいたリポジトリは OSS リポジトリと同じように私の方で巡回して見ていくことになります。その過程で、Pull Request のレビューコメントを行ったり、RuboCop のアップグレードなどの困りごとの相談に乗ったりしています。また、Ruby/Rails を軸としたコミュニティ横断的な足まわりに関する Pull Request を送ることがあります。

やらないこと

お客様によって対応を変えるということをしないため、オンラインのみの対応としており GitHub でのやりとりがベースとなります。とはいえ定期的に何か口頭で話したいといったご要望など、そちらは応相談という形になります。また、開発案件としていつまでにどこまで何を行うかといった機能開発は行いません。

どうして始めたの?

私は、アジャイルソフトウェア開発を軸に、Ruby on Rails のお仕事は Rails 初期から行っており、近年は OSS まわりでも日常的に開発を続けています。生涯で見ることのできるプロジェクトの数は限られていることもあり、これまでとこれからのノウハウをひとつでも多くのプロジェクトに届ける機会として、今回のサービスを始めてみました。

ちなみに企業として OSS に関わってみたいけれど、OSS への関わり方がわからないという Ruby/Rails を活用の企業様にもオススメです。どういうことかというと、まず私は対象リポジトリを RuboCop で実行してみるため、そこで見つかった RuboCop のバグは RuboCop 本体に取り込みます。そのように OSS 開発者がコードベースに触れることで OSS を改善してくという流れもありますので、このような視点もあわせてぜひご検討ください。

お問い合わせ先

そのほかの概略は以下のサービスページに記載しております。気になったり、後日に思い出した折りは、こちらまでお問い合わせください。

agile.esm.co.jp


アジャイル事業部のRubyアジャイル受託開発は、アジャイル開発を10年以上続けて培った、決して手法や方法論ではまとめきれない、実践知や価値観、それを届ける人で構成されています。Ruby とアジャイルソフトウェア開発を通じてコミュニティと共感していけるお客様とエンジニアを絶賛募集しています。

agile.esm.co.jp

Rails / OSS パッチ会オンライン 2024年1月のお知らせ

2024年1月の Rails / OSS パッチ会を 1月17日(水)に Discord でオンライン開催します。

この会をひとことでいうと、日頃のお仕事で使っている Rails をはじめとする OSS について、upstream にパッチを送る会です。

今回は Ruby と Rails のコミッターである顧問の a_matsuda は不在ですが、例えば Rails に送るパッチのネタがあるけれど、パッチを送るに適しているかの判断やパッチを送る流れが悩ましいときなどパッチ会メンバーに相談して足がかりにするなどできます。

開催時間は 17:00-19:00 となりますがご都合のあう方はぜひご参加下さい。

Discord の Rails/OSS パッチ会サーバーへの招待 URL は以下です👇

discord.gg

先月リリースされた Ruby 3.3 などに関する話題があるかもしれません。

RubyKaigi 2024 CFP の締切が今月末ということもあり、CFP へのプロポーザルに向けた OSS 活動を進めたい方や、これからパッチ会に参加してみたいという方、OSS 開発者間の会話に興味があるので聞いてみたいという方もお気軽にどうぞ。


永和システムマネジメントでは、Ruby とアジャイルソフトウェア開発を通じてコミュニティと成長したいエンジニアを絶賛募集しています。

agile.esm.co.jp

RubyKaigi 2024 に ESM メンバーが11人現地参加予定です

2024年5月15日 (水) から 5月17日 (金) にかけて、沖縄県の那覇市で開催される RubyKaigi 2024 に弊社 ESM メンバーが 11 人現地参加する予定です。

rubykaigi.org

現在2023年12月時点の参加予定メンバーは以下です。

今年も何名かのメンバーは CFP プロポーザルを考え始めたり、RubyKaigi スポンサーとして何か企画できないかアイデアを出し始めているところです。

RubyKaigi 2024 まで残り5ヶ月を切りました。オープンなコードを書いていきましょう。


永和システムマネジメントでは、Ruby とアジャイルソフトウェア開発を通じてコミュニティと成長したいエンジニアを絶賛募集しています。

agile.esm.co.jp

RubyConf Taiwan 2023 で発表してきました

こんにちは。@junk0612です。

この記事は ESM アドベントカレンダーとは特に関係のないカンファレンス参加記事ですが、せっかくここを見に来たのならぜひついでに覗いていってください。アジャイル事業部メンバーに限らず、面白い記事がたくさん書かれています。

さて、12/15 と 12/16 に行われた RubyConf Taiwan に永和から @koic, @ima1zumi, @fugakkbn と4名で参加してきました。また、個人的には4回目にして初めてスピーカーとしての参加でした。いつもながら、旅費は全員会社負担です。そのため、今回はスピーカースポンサーとして会社ロゴが掲載できました。 今回はその裏側の部分を書いてみようと思います。

発表することにした経緯

8月下旬、RubyConf Taiwan チーフオーガナイザーの @ryudoawaru さんが仕事で日本に来るとのことで、個人的に交流があったので声がかかり、@koic と3人でご飯を食べに行きました。その場で、RubyConf Taiwan をオンサイトで開催する方向で動いていることを聞き、「プロポーザル出しませんか?」と誘っていただきました (@koic は隣でニヤニヤしてました)。たしかその場では、明確な発表のイメージができなかったので「いや〜ちょっと考えてみます〜」みたいな歯切れの悪い返事をした気がします。

ですがその後、大阪 Ruby 会議での発表を経て「この発表の英語版を発表すればいいかもしれない」と思いました。初めての英語かつ海外での発表なのでいくつか不安があったのですが、どれも解消できたからです。

  • 内容を考えてから英語にするのは大変→内容は決まっているし日本語スライドもあるので、英語化だけに専念できる
  • 発表時間が見積もりづらい→日本語で30分の発表だったので、英語化によるバッファが10分あると考えての40分とするのは妥当そうに思える
  • 新しいネタを考えるのが難しい→聴衆がほとんど被っていないので、同じネタでも面白がってくれる

そんなわけで、プロポーザルを出すことにしました。内容が決まっていたので、わりとすんなり書けました。

書いてる途中にオーガナイザー自ら「進捗どうですか?」してきてくれて若干ビビりました

発表まで

11月頭に発表者が公表されましたが、その時期は RubyWorld Conference に向けて準備中の時期でした。これが終わってからでも発表まで1ヶ月あることや、あまり大きなことはしていませんが一応スポンサー系の旗振り役をやっていたこともあり、RubyWorld Conference が終わるまではいったんそちらに注力することにしました。@ryudoawaru さんも参加していたほか台湾での日本人スピーカーが多く集まっていたので、集まって写真を撮りました。

毎晩飲み歩いたのが災いしたか、松江から帰ってきた日に重い風邪を引いて1週間寝込んでしまっていきなり暗雲が立ち込めましたが、ChatGPT による自然な英文への翻訳のおかげで (会社補助には本当に感謝しています)、無事スライドの英訳とトークスクリプトの作成を終わらせて台湾に向かいました。

到着後ホテルへのチェックインを済ませ、スライドの最初に仕込むネタのために永和区1に写真を撮りに行きました。翌朝永和豆漿大王2でも写真を撮って、準備を整えました。

発表

発表に使用したスライドはこちらです。

当初の予定通り、大阪Ruby会議での発表とほぼ同内容になりました。違いとしては、Lrama 独自の機能として Parameterizing rules を紹介したこと (@ydah_ さんお疲れ様でした)、Future Work が内部パーサーの Racc 化から IELR パーサーの生成に変わったことくらいで、あとは文章の配置や図のリファインメント程度です。

たった10分で文脈自由文法を解説している @junk0612

始まるまでは、トーク内容がニッチなのと裏番組が中国語の発表だったため、あまり聴衆は多くないのではと思っていましたが、実際にはたくさんの参加者に聞いてもらえてとてもありがたかったです。また、質疑応答では聴衆にいた @hsbt さん、@yui-knk さんにそれぞれ補足してもらったり代わりに回答してもらったりというありがたいことも起こりました。この場を借りてお礼申し上げます。

発表以外のこと

RubyWorld Conference で一度痛い目を見ておきながら、今回も四日四晩飲み歩いてしまいました。ただ、少ない日本人参加者同士でつるんで飲んでいたため、RubyKaigi などでは意外と味わえない「特定少数と密度の濃い話を毎晩する」という経験ができたのは面白かったです。おかげさまでまたパーサーに詳しくなれました。

コロナ禍を挟みましたが、台湾は相変わらずリーズナブルで美味しいご飯がたくさんあるところでした。今年は久しぶりだったのもありあまり冒険はせず定番のものを食べたりお土産にしたりしましたが、次はいろいろ開拓していきたいなと思いました。

今回もとても楽しかったです。昔から通っていただけに、またオンサイトで開催されたこと、そしてそこで発表できたということも良かったなと思います。特にチーフオーガナイザーの @ryudoawaru さん、お疲れ様でした && 次回も楽しみにしています!

では、またどこかのカンファレンスでお会いしましょう。


永和システムマネジメントでは、Ruby とアジャイルソフトウェア開発を通じてコミュニティと成長したいエンジニアを絶賛募集しています。

agile.esm.co.jp


  1. 台北市の南にある新北市の区の一つで、台北市と隣接している。
  2. おそらく永和区の地名から取られている台湾の豆乳屋さん。朝早くから開いており、台湾では豆乳屋やお粥屋で朝ごはんを外食するのが普通の文化らしい。