電通総研 テックブログ

電通総研が運営する技術ブログ

VS Codeで作るErlangアプリケーション開発環境

みなさんこんにちは、電通国際情報サービス(ISID)Xイノベーション本部ソフトウェアデザインセンターの佐藤太一です。

皆さんは最近発売された『実践プロパティベーステスト ― PropErとErlang/Elixirではじめよう』はもう読みましたか?

この本はErlangやElixirを使ってプロパティベーステストというテスト手法について具体的なコードを使って実践的に学習できる本です。非常に素晴らしい本ですが、難しい部分も多いため私は少しずつ読んでいる所です。

この記事では、この本を読むにあたってサンプルコードを動かすための環境を使っているOSに依存せずに作成する方法を説明します。

事前の準備

この記事が前提とする環境について軽く説明します。

まず、 VS Code を事前にインストールしておいてください。

次に、Docker Desktopをインストールして動作する状態にしてください。基本的には単にインストーラを実行すれば動作する状態になります。

そして、VS Codeに Dev Containers拡張をインストールしておいてください。

最後に、作業用のプロジェクトディレクトリを作成してください。ここでは、pbt というディレクトリを作成してプロジェクトのルートディレクトリとしています。

最小限のDev Container

まずは、Dev Containerを使ってErlangが提供する公式のDockerイメージを使った開発環境を作成してみましょう。

プロジェクトのルートディレクトリに、 .devcontainer というディレクトリを作って、その中に devcontainer.json というファイル名で以下の内容を保存します。

{
  "name": "devcontainer-erlang",
  "image": "erlang:slim",
  "containerEnv": {
    "TZ": "Asia/Tokyo"
  },
  "runArgs": ["--init"]
}
  • name の値は、分かりやすい名前なら何でもいいです。ここでは、devcontainer-erlang としています。
  • image の値は、erlang:slim としています。これは公式のイメージ名です。
  • containerEnv の値は、コンテナ内で参照される環境変数です。ここではタイムゾーンが Asia/Tokyoになるよう設定しています。時刻に起因する問題の調査は難しいので、ここで明示的に設定しています。
  • runArgs の値は、 --init を渡すことでDockerが /dev/init というシグナルハンドリング用のプロセスを起動してくれます。これによってコンテナを安定的にシャットダウンできます。

devcontainer.jsonを編集する環境の構築

ここから、devcontainer.json を編集しながら開発環境を構築していくので、まずは快適にjsonファイルを編集できるようにしましょう。

devcontainer.jsonには、Dev Containerとして起動したVS Codeを構成するための設定項目がありますので、それらを編集します。

{
  "name": "devcontainer-erlang",
  "image": "erlang:slim",
  "customizations": {
    "vscode": {
      "settings": {
        "editor.renderWhitespace": "all",
        "[json][jsonc]": {
          "editor.defaultFormatter": "esbenp.prettier-vscode",
          "editor.formatOnSave": true,
          "editor.codeActionsOnSave": {
            "source.fixAll": true
          }
        }
      },
      "extensions": ["esbenp.prettier-vscode"]
    }
  }
}

customizations というキーがDev Containerの構成を行うための設定項目です。この中にvscode という項目がありますね。

settingsの中では、VS Codeの設定項目を管理します。

  • editor.renderWhitespace の値として、 all を設定しているのは、ファイルの中に紛れ込んだ全角スペースを見つけやすくするためです。私たちがIMEを使っている以上、意図しない場所に全角スペースが入り込んでしまい、それによって理解が困難なエラーメッセージを読むことになるのは避けられません。全角スペースが見えていれば、そういったドハマりから抜け出しやすくなります。
  • [json][jsonc] の値として、いくつか設定しています。ちなみに、jsoncは、JSON with commentsの略称です。
    • editor.defaultFormatter の値として、esbenp.prettier-vscode を設定しています。これによってprettierを使ったフォーマットが行われます。
    • editor.formatOnSave の値として、trueを設定することでファイル保存時にフォーマットが行われるようにしています。
    • editor.codeActionsOnSave の値として、source.fixAll を有効化することで自動的に補正できるフォーマットエラーをprettierが積極的に補正してくれます。

extensionsの中では、Dev Containerとして起動されたVS CodeにインストールされるVS Code拡張を列挙します。ここでは、JSONを自動フォーマットするための esbenp.prettier-vscode を設定しています。

ErlangVS Code拡張

次は、Erlang用のVS Code拡張を追加します。マーケットプレイスを確認するといくつかの拡張がありますが、一番利用者の多いものを今回は使います。

devcontainer.jsonのextensionsに拡張を追加すると、以下のようになります。

{
  "name": "devcontainer-erlang",
  "image": "erlang:slim",
  "customizations": {
    "vscode": {
      "settings": {
        "editor.renderWhitespace": "all",
        "erlang.formattingLineLength": 200,
        "[erlang]": {
          "editor.defaultFormatter": "pgourlain.erlang",
          "editor.formatOnSave": true,
          "editor.codeActionsOnSave": {
            "source.fixAll": true
          }
        },
        "[json][jsonc]": {
          "editor.defaultFormatter": "esbenp.prettier-vscode",
          "editor.formatOnSave": true,
          "editor.codeActionsOnSave": {
            "source.fixAll": true
          }
        }
      },
      "extensions": ["pgourlain.erlang", "esbenp.prettier-vscode"]
    }
  }
}
  • erlang.formattingLineLength の値として、200を設定しています。この設定項目はドキュメントには記載がないので、私の設定値をここに書いています。
  • [erlang] の値として、いくつか設定しています。何をしているかは[json][jsonc] の時と同じです。

これでErlangのアプリケーション開発環境は完成です。しかし、本を読み進めていくと早々に問題にぶつかります。

テスト用プロファイルで使うライブラリをエディタに認識させる

書籍では、PropErというライブラリをrebarというビルドツールに構成するように指示されます。

その結果、rebar.configを以下のように構成します。

{project_plugins, [rebar3_proper]}.

{profiles, [
    {test, [
        {erl_opts, [nowarn_export_all]},
        {deps, [proper]}
    ]}
]}.

{erl_opts, [debug_info]}.
{deps, []}.

rebar3では、依存ライブラリをプロファイル毎に管理できるようになっています。

そして、 propertest プロファイルでのみ参照されます。

ダウンロードされた依存ライブラリは、プロジェクトのルートディレクトリにある _build ディレクトリ以下に格納されています。

この状態だと、rebarによるビルドは成功するのですが、エディタ上で can't find include lib "proper/include/proper.hrl” といったエラーが出力されます。

このエラーを解決するためVS Codeのエディタ上でも、testプロファイル以下にダウンロードされたライブラリを参照するように設定を追加します。

変更した後のdevcontainer.json は以下のようになります。

{
  "name": "devcontainer-erlang",
  "image": "erlang:slim",
  "customizations": {
    "vscode": {
      "settings": {
        "editor.renderWhitespace": "all",
        "erlang.formattingLineLength": 200,
        "erlang.includePaths": ["_build/test/lib"],
        "[erlang]": {
          "editor.defaultFormatter": "pgourlain.erlang",
          "editor.formatOnSave": true,
          "editor.codeActionsOnSave": {
            "source.fixAll": true
          }
        },
        "[json][jsonc]": {
          "editor.defaultFormatter": "esbenp.prettier-vscode",
          "editor.formatOnSave": true,
          "editor.codeActionsOnSave": {
            "source.fixAll": true
          }
        }
      },
      "extensions": ["pgourlain.erlang", "esbenp.prettier-vscode"]
    }
  }
}
  • erlang.includePaths の値として、ライブラリを格納しているディレクトリの相対パスを記述しています。

まとめ

ここまで、Dev ContainerでErlangアプリケーションの開発環境を構築する方法について説明してきました。

普段あまり使っていないプログラミング言語でも、Dockerベースのコンテナ技術を使えば簡単に開発環境を構築できることがお分かりいただけたんじゃないでしょうか。

特に私が普段使っているWindowsではインストーラを使ったバイナリのインストールは後腐れが残り易いので、本を読み終わったら全てを片付けられて副作用のないDev Containerは非常に便利です。

この記事を読んでいただいたあなたも是非、クリーンな開発環境を構築してプロパティベーステストという応用可能性の高いテスト手法に習熟できることを願っています。

この記事で紹介している開発環境の構成ファイル

最後に作った構成ファイルを紹介します。

.devcontainer/devcontainer.json

{
  "name": "devcontainer-erlang",
  "image": "erlang:slim",
  "customizations": {
    "vscode": {
      "settings": {
        "editor.renderWhitespace": "all",
        "erlang.formattingLineLength": 200,
        "erlang.includePaths": ["_build/test/lib"],
        "[erlang]": {
          "editor.defaultFormatter": "pgourlain.erlang",
          "editor.formatOnSave": true,
          "editor.codeActionsOnSave": {
            "source.fixAll": true
          }
        },
        "[json][jsonc]": {
          "editor.defaultFormatter": "esbenp.prettier-vscode",
          "editor.formatOnSave": true,
          "editor.codeActionsOnSave": {
            "source.fixAll": true
          }
        }
      },
      "extensions": ["pgourlain.erlang", "esbenp.prettier-vscode"]
    }
  }
}

執筆:@sato.taichi
Shodoで執筆されました