ふと思い立ち、SalesforceのApex言語のローカル実行環境を作っています。

tzmfreedom/apex_parser2

まだまだリリースにはほど遠いのですが、単純なコードであればある程度は動く状態になってきているので、モチベーション維持のためにここらで紹介記事を書きたいと思います。

何ができるのか

こういうApexのコードがローカルで動くようになります。

コンパイルできるかどうかをAPI経由で確かめるのではなくローカルでシンタックスチェック、型チェックなどを実行しつつ、実際にコードの実行もできるというヤーツ。

ローカルで実行できて何が嬉しいのか

  • 個人単位の開発効率が上がる
    • 動作確認をWeb経由で行う必要がない
    • シンタックスチェック、型チェックをWeb経由で行う必要がない
    • テストコードをローカルで高速に実行できる
    •  デバッグがしやすい
      • ローカルなのでステップ実行可能なデバッガが作れる
      • デバッグログの表示内容をコントロールできる
        • 例えばオブジェクトをSystem.debugしたときにprettyprintするなど
        • (デバッグログはログでしかないので、実際のSalesforceでの動作と差異が有ってもそんなに問題じゃないはず)
  • チーム単位の開発効率が上がる
    • ローカルでApexを実行できるのでgitなどのVCSを使った開発ができるかも…?

なんで作ろうとしたのか

Salesforceのアンチパターンをまとめた技術書籍を書こうとメモ書きしていたところ、 Apexはローカルで実行できないので○○ みたいなフレーズを結構書いていて、「あれ、これそもそもローカルで実行できたら解決すること多いのでは?」と思ってチャレンジしてみました。言語実装にも興味があったんですよねー。

利用技術

ANTLRというLL(*)なパーサジェネレータを使ってNode.jsで実装しています。

Rubyが好きなのでRaccというLALR(1)なパーサジェネレータを使ってRubyで実装しようと思ったんですが、LALR(1)だとジェネリクスのシンタックスのパースがかなり厳しかったので断念。

ANTLRはJava, C#, C++, Go, JavaScript, Pythonに対応していて、Salesforce界隈でよく使われているCLI・ライブラリであるsfdxjsforceがJavaScriptを採用していることもあり、JavaScriptを採用しました。Salesforce開発者はnodeを入れればOK!みたいな世界観ができるといいなぁ、みたいな。

WebのREPLを開発するときも静的ファイルだけで構成できそうですし。

今のところできることなど

  • 簡単なコードであれば何となく動くような感じ
  • デバッガ作った(後述)
  • 標準のクラスに関しては実装中(数が多い…)
  • modifier系(abstract/virtual/private/protected)はこれから
  • SOQLと各DMLの実行基盤もこれから
  • PoC的な感じで実装しているのでコードはかなり雑

今すぐ試してみたい方へ

こんな感じでcloneして

bin/landのコマンドを叩けばOK

Javaと同じようにエントリポイントとなる関数を定義する必要があって、上の例だとHogeクラスのactionメソッド(クラスメソッド)を実行するようになります。ここらへんは仕様策定中。

まだまだ動かないパターンが多いしコードもグッチャグチャなのでnpm化まではもう少しかかりそうです。

ローカル環境だからできる機能拡張

ステップ実行が手軽にできる環境があると便利ですよね。Rubyだとbyebugというステップ実行可能なデバッガがあるんですが、これと同じことを実現したいなーと思ったので作ってみました。こんな感じでデバッガを仕込めます

// debugger というコメントがデバッガになります。コメントにデバッガの機能を仕込むことで、そのままデプロイしても通るようになっています。

実際にこのコードを走らせると対話式のデバッガが起動して、next とかstepとか打つとステップ実行できたり、showコマンドで変数を確認できます。

これ以外にも // xxx のコメント構文を使ってマジカルなことをしたいと思ってます。

その他色々

思い立ったのが6/18

ANTLRで実装し始めたのは7/2

なので3〜5週くらいで実装していた感じなのですが意外と形になっていてびっくりです。

これからは

  • SOQL/DML周りの実装
  • 標準ライブラリの実装
  • 不具合潰し・リファクタリング

を軸に実装を進めていき、9〜10月くらいには公開できると良いかなーと思っとります。

ASTという意味合いだとローカル実行基盤以外にも、シンタックスハイライトしたりlintツールや補完ツールを作れたりもします。ここらへんは言語実装が落ち着いたら着手したいなーと思っていますが興味がある方はANTLRで実装してみるのも良いかもしれません。今のANTLRの文法ファイルはこれを使ってます↓

apex_parser2/apex.g4

あと、今のアプローチだとざっくりこんな感じで

  1. AST作る
  2. ASTから型チェックや変数の二重定義などのチェックをする
  3. ASTを実行

毎回1の工程から処理するので標準ライブラリのクラスが増えたりApexのファイルが増えると実行時間が長くなります。

本当は2でチェックしたものをバイナリか何かで保存できれば1, 2をスキップできるので高速に動きそうな感じはするのですが良い方法がないか模索中です。今のところメモリに常駐させて、ファイル変更があったら都度1, 2をそのファイルに対してのみ行う(差分に対してのみ適用する)ことで時間短縮しようかな、と思っていたり。Railsのspringがそういう考えで実装されているのでそれを踏襲できると良いかなと。さすがにバイトコードに変換するとかまではやりません(というかできないw)

あと、言語実装が専門な人ではないので私のクソパーサを見て「俺だったらもっと良いの作れる!」と後発で良いのが出るかもしれませんし、もしかしたら今年のDreamforceあたりでローカル実行環境とかそろそろ出てくるのでは?とか思っていたりします。リモートデバッガもできたようですし。まぁそれでも今の取り組みは全然無駄にはならないと思っているので、そこらへんは考えずに気軽にやってます。