新たな開発プラットフォーム "Dark/Darklang" を実際に触ってみて

# はじめに
先日、私が以前に申請していたDarkのプライベートベータ版に漸く招待されたので、実際に触ってみた感想を述べよう思います。

# 1. Darkとは?
Darkとは、**Ellen Chisa**、そしてCircleCIの創業者である**Paul Biggar**によって設立された会社で開発されている**「偶発的な複雑さ」**を無くし、バックエンドWebサービスを構築するための総合的な**プログラミング言語**であり、**エディタ**であり、**インフラストラクチャ**です。呼称するならば、総合的なソフトウェア開発プラットフォームみたいな感じです。Web上にエディタが展開され、そこで全ての開発を行える為、開発ツールやパブリッククラウドと言った多くのテクノロジーを直接触る必要はありません。

また、最大の特徴としては**デプロイレス**です。デプロイレスとは、入力したものが即座にデプロイされ、本番環境ですぐに使用できます。Darkはインタープリタをクラウドで実行され関数またはHTTP/イベントハンドラで新しいコードを作成すると、抽象構文ツリーの差分(エディターとサーバーが内部で使用するコードの表現)をサーバに送信し、次にそのコードを実行します。その為、デプロイメントはデータベースへの僅かな書き込みで済む為、瞬時且つアトミックです。この様に、デプロイを可能な限り最小化する事で**最大50msの高速デプロイ**を実現しています。

※デプロイレスに関する詳細は本記事下部の参考文献に記載

# 2. どんな開発に向いているのか
Darkは大きな目標として、「ソフトウェアの構築を100倍容易にすることでコーディングを民主化し、次の10億人がコーディングできるようにする」と挙げているが、初期段階では以下のような領域をターゲットにしています。

* モバイルアプリや、React, Vue, Anglarで記述された単一ページのWebアプリ等のクライアントアプリのバックエンド
* 既存のマイクロサービスベースのアーキテクチャで新しいサービスを構築すること

一方で、組み込みシステムや、定理証明、機械学習モデルなどは今後サポートする予定は無いとの事です。

# 3. 実際に動かしてみる
実際にDarkのチュートリアルを参考にして、「日付レポート」のAPIを実装していきます。

Darkにログインするとエディタが立ち上がります。画面は非常にシンプルで、サイドバー、ユーザ情報(右上)、ドキュメント(右下)のみである。基本的な操作は画面をクリックすると以下の図の様に機能の選択画面が表示されます。開発は、この画面をキャンバスの様に使用して都度、自分の使用したいものを選択・追加してく事で開発していきます。

<img width="1434" alt="Screen Shot 2020-03-19 at 4.09.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/a3b942ad-bf71-df9f-5cde-e18cebc0f7c1.png">

## 3.1. Hello World
Hello Worldを作成してみます。手順は非常にシンプルです。

![ezgif.com-video-to-gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/484f973b-85f1-7707-85aa-41b800e90935.gif)

画面をクリックし、メニューが開かれた状態で`hello`と入力すると、`New HTTP handler named /hello`とメニューに表示されるので、それを選択すると`/hello`ハンドラが作成されます。後は、リクエストメソッドと、valueを書くだけで完成です。作成したものは、右上の設定から`Open in new tab`で即時に確認する事ができます。

また、`value`が未記入の場合、`<Incomplete> Your code needs to return a value in the last expression`とエラーが表示されます。

※エンドポイントは、デフォルトでは`USERNAME-gettingstarted.builtwithdark.com`となりますが、`USERNAME-.builtwithdark.com`の2つ存在しました。エンドポイント変更はユーザ画像をクリックし、`Account/Canvas`から切り換える事ができます。

【2020/03/22追記】
エンドポイントを書き換える事でプロジェクトを複数作成する事が可能で、新規プロジェクトを作成する際はエンドポイントを書き換えて更新すると良いです。

## 3.2. 演算
次に簡単な演算を行い、演算結果を渡してみます。

先程、同じ様にHTTPハンドラを作成し、リクエストメソッドを`GET`、ルートを`/add`に設定しました。

演算処理は、演算子を使用して簡単に記述する事も可能ですが、変数を宣言して行うことも可能です。

![ezgif.com-video-to-gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/43b18e2b-b3b7-48b1-c0d1-98dda789118a.gif)

また、Darkではハンドラを作成すると、以下の様に各々の値を瞬時に確認する事ができます。

<img width="474" alt="Screen Shot 2020-03-20 at 15.20.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/55c1b3ad-751a-98ee-73ab-3073f7c75b6d.png">

`9(画像下部)`と出力されている場所は、このハンドラの戻り値です。`5(画像左部)`はカーソルが置かれている位置の式の結果を表示しています。整数の場合では利便性を感じませんが、変数の場合は即座に結果を確認できます。

## 3.3. REPL

REPLを作成する際も、同様に選択画面からREPLを選択し作成していきます。今回は、敢えてエラーを起こしてその挙動も確認してみる事にします。

`httpclient`と入力すると、HTTPClientのすべての標準ライブラリ関数、署名、およびdocstringが表示されます。今回は、`HTTPClient::post`を使用しようと思うので、`httpclientpost`まで打つと表示されました。Darkはオートコンプリートを行ってくれるので、正確なテキストを入力する事は不要です。

`HTTPClient::post`を選択すると、受け取る為のパラメータ(`URI`,`Body`,`Query`, `Headers`)を自動的に作成され、それらを全て入力するとエディター内から式を実行できる実行ボタン(`HTTPClient::post`の右側の灰色の三角形)が表示されます。

![ezgif.com-video-to-gif (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/effaf0fb-0f36-b854-ff25-13e86f0f2b66.gif)

エンドポイントは今回、`USERNAME.builtwithdark.com`を使用したので、以下の様に入力します。

```http
https://USERNAME.builtwithdark.com/test
```

その他、パラメータを入力して実行しようとすると`404`がレスポンスとして表示されます。これは、エンドポイント`/test`がキャンバス上に存在しない為です。この結果は、サイドバーの404セクションからも確認できます。

<img width="334" alt="Screen Shot 2020-03-20 at 16.47.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/897971e9-3f7e-7615-60ca-d8f6b118a143.png">

一方、キャンバス上ではエラーはこの様に表示されます。

<img width="713" alt="Screen Shot 2020-03-20 at 16.47.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/4833e3fb-c28a-df85-f63c-d743bb1ec662.png">

## 3.4. データストア
まず、先程のエンドポイントでのエラーを解決する為に、DarkではHTTPリクエストのトレースを使用してエンドポイントを構築します(**トレース駆動開発**)。404セクションにあるルート`/test`の右側にある青色の+ボタンを押すと、`POST`メソッドのルート`/test`が作成されます。

![ezgif.com-video-to-gif (2).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/d9b2230f-4146-726b-87c6-b6e5b745f9fc.gif)

作成されたものを確認してみると、`Body`を含むREPLで設定したリクエスト情報が完全にトレースされている事が確認できます。

<img width="745" alt="Screen Shot 2020-03-20 at 17.09.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/896323a7-e909-f1f8-9157-6668b5fdcf7b.png">

このリクエストを直接処理し、`let data = request.body`を入力して取得した情報をレコードに保存します。ここでも、オートコンプリートを活用して記述していきます。

![ezgif.com-video-to-gif (3).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/b7069f30-675f-47f5-ad77-fb08c97eb752.gif)

データストアは、HttpClientライブラリと同様に、空白に「DB」と入力すると、すべてのデータストア関数がプルアップされます。今回の場合では、`db::set`を使用します。

データストアの作成は、サイドバーかキャンバス内をクリックして作成が可能です。今回は、`Requests`と言うデータストアを作成しました。(小文字で入力して作成しても、最初の1文字目は大文字に変換してくれる様である)

Darkのすべてのデータストアはキー値ベースであり、キーをレコードの一意の識別子として使用します。今回の場合であると、`data`、`time`のキーを作成した場合は以下の様になります。

```json
{
  key1: {
          data: {
                  test: "test2"
                },
          time: 
        },
  key2: {
          data: {
                  test: "test1"
                },
          time: 
        }
}
```

最初のパラメータは、挿入するレコードです。これは、日付と時刻のスキーマと一致します。Darkでは、`DB::set`のすべてのフィールドを含める必要があり、上記のデータと`Date::now`関数を挿入して時間を取得しています。2つ目はキーであり、各オブジェクトに一意のキーが必要です。この場合、`db`と入力すると、組み込みの`db::GenerateKey`関数が取得できます。3つ目は、データストア名を指定します。データストアの名前はオートコンプリートで表示されます。

最後に、`DB::set`を実行してみると以下の様にデータストアにレコードが挿入され、スキーマがロックされます。

<img width="850" alt="Screen Shot 2020-03-20 at 17.59.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/7393016f-f3d0-834f-9abd-5909e7e54e81.png">

## 3.5. CRON
今回は、`dailyReport`と言うの名前のCRONを作成します。

日付レポートを作成する為には、現在の時間と比較する必要があります。まず、変数`timeSeconds`を用意し`Date::now`を設定します。次に、比較の為に秒単位の時間が必要の為、`Date::toSeconds`も設定します。関数はパイプで繋げる事ができます。(`|`と入力すると、`|>`と表示される。)

リクエストの取得は、`DB::getAll`を使用し、取得したいDBテーブル(`Requests`)を指定します。リクエストはList型で取得されます。入力後に、実行してみると以下の様にリクエストが取得されている事が確認できます。

![Screen Shot 2020-03-21 at 13.41.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/67a6250f-a75f-bc73-04f9-1448b23212fb.png)

次に、`List::filter`を使用してリクエストのフィルタリングを行います。`List::filter`では、フィルタリングするリスト名と、匿名関数を設定します。

![Screen Shot 2020-03-21 at 20.44.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/dd34782c-b5bc-bbc5-1a7d-28666eedd003.png)

匿名関数では、リクエストが今日の情報であるかどうかを確認します。

変数`requestSeconds`は、リクエスト内に内包されている時間`date`です。リクエストの時間は秒に変換する必要がある為、CRONの最初の行と似ているが、`val.time`でリクエストの時間を取得しパイプで`Date::toSeconds`を繋げて変換しています。

変数`difference`は、現在の時刻とリクエストの時間の差分を計算しています。 そして、差分の結果が24時間以内(86400秒)であるかどうかを判別します。

最後に、`emit`を使用して、バックグラウンドワーカーにリクエストを送信します。`emit`では、イベント名(`todayRequests`)と、WORKER名(`StoreReport`)を指定して送信を行います。

## 3.6. WORKER
CRONを実行すると、WORKERは存在していないので404セクションに表示されます。その為、先程と同じ様に404セクションから`StoreResort`を選択すると、既に名前がついた状態で作成されます。作成されたWORKERにカーソルを合わせると、CRONによってトリガーされイベントが表示されます。

![Screen Shot 2020-03-21 at 17.08.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/03735e30-bb97-eca8-3e5b-36f9d27a20ee.png)

実際に、WORKERの機能を実装すると以下のようになります。

![Screen Shot 2020-03-21 at 17.44.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/ef946c59-2555-b2b0-e3a8-6cdd64448f8c.png)

レポートでは、`MM-DD-YYYY`の表記でデータを保存する為、現在時刻を取得し、それぞれを分割して変数`humanDate`でフォーマット変換を行いました。

※`+`はint型の場合でのみ使用できる様で、String型の場合は`++`を使用する事で文字列を連結する事ができます。

変数`data`では、リクエストに内包されている`data`のみを取得しています。`List::map`を使用する事で、リスト内のオブジェクトのコレクションに対して操作する事ができます。

レポートの保存は、新たに`DailyReport`と言うデータストアを作成しているが、外部APIを使用する事も可能です。

以上で、実装は終了です。ここまでの実装したものを並べると以下のようになります。

![Screen Shot 2020-03-21 at 18.17.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/1fbd5544-7e26-ad58-2223-6eda1156a053.png)

## 3.7. 動作検証
REPL内で記述した、BODY部分を`test 1`から、`hello Dark!`に変更して実行してみます。

![Screen Shot 2020-03-21 at 18.43.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/0d2e0797-50ce-040c-430d-ca75246486e8.png)


実行すると、`/test`ハンドラでは新しいトレースドットが表示され、リクエストのBODYが、`hello Dark!`になっている事が確認できます。

![Screen Shot 2020-03-21 at 18.49.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/1e1bcf6f-4a9c-4c7f-c229-20d68b3ecd4d.png)

データストアも同じく、DBに追加されたレコードが表示されます。

![Screen Shot 2020-03-21 at 18.53.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/85ab69ca-33b4-7bb8-4c6a-869221b1496e.png)

CRONの方も確認してみると、DBのレコードが全て取得できている事が確認できていますが、時系列毎にソートして表示されてはいない為探すのに苦労しました。筆者が不必要に連打したのが原因でもありますが、レコードが増えていく事が想定されると目を通すのには可読性が悪く、少し労力が掛かるなと感じました。

![Screen Shot 2020-03-21 at 19.02.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/15cc7c3e-b2fb-4217-b780-de05e51dbfde.png)

WORKERも同じ事が言えると思います。しかし、Eventは実行された時系列毎に保存されており、前回との差分の確認や以前のデータの内容を確認する事ができます。

![Screen Shot 2020-03-21 at 19.07.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/885e6a99-ae0a-f015-4070-15707375b392.png)

最後に、日付レポートのデータストアも確認すると、日付毎にレコードが登録されている事が確認できます。

![Screen Shot 2020-03-21 at 23.53.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/ca1b3012-d7e5-3ea7-881a-83d367fdf1ec.png)

また、新たにREPLを作成し日時レポートとその内部の項目数を取得してみました。実行してみると、`DailyReport`から日付毎にレポートを取得する事ができます。試しに異なる日付のレコードも登録した所、そちらも同じく取得する事ができました。

![Screen Shot 2020-03-21 at 20.48.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/b538c7fe-4efb-3ccb-9c0a-89cbe0a2b437.png)

ハンドラなどを削除すると、Deletedセクションが表示されます。Deleteセクションから削除されたハンドラやデータストアを見ることができ、復元すると即座にデプロイし直され元の状態に復元する事ができます。

![ezgif.com-video-to-gif (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223371/14417546-b50c-57e9-980c-28b97596f336.gif)

# 4. 総評
初めてDarkを触り、直感的操作で開発を行う事ができました。確かに、初期段階ではDarkのツールセットについての学習コストは発生するものの、従来の開発言語を覚える程では現段階は無いと感じます。

また、コードを書くことと並行してトレーシングが行われ、Dark内で作成したものはオートセーブされる為、ウィンドウを閉じても再度立ち上げると以前の状態から再開する事ができるので逐一保存する面倒もありません。

デプロイレスと言う指向は、これまでいくつかのサービスで実装しようと試みて来ていましたが、Darkが初めての成功例ではないでしょうか。開発者は、アプリケーションのコードを書くだけで良く、書き終わったコードは既にホストされていると言うのは非常に有り難い事です。CircleCIを開発してきたPaul Bigger氏だからこそ、デプロイに深く精通し、その中に存在する課題を解決する策として見出せたのだと思います。

ベータ版ではあるが、既にある程度の開発も可能でReact SPAや、Slackbotの開発もできるようなので今後試しに実装しようと思います。

しかし、バグもまだ存在しているのでこれからの改善に大きく期待すると共に今後の開発に貢献していけたらと思います。

最後に、本記事を見てDarkを触れてみたいと感じた人が少しでも増えてくれれば幸いです。ベータ版は、Darkの公式サイトから登録が可能で招待されるまでに時間は掛かります(筆者はベータ版開始から大体2,3ヶ月待った)が是非この機会に登録してみて下さい。

# 5. 謝辞
本記事を作成するに至り、快く承諾してくれたCEOのEllen Chisaに深く感謝いたします。

# 参考文献
* [Dark (Official Site)](https://darklang.com/)
* [What is Dark?](https://medium.com/darklang/the-design-of-dark-59f5d38e52d2)
* [How Dark deploys code in 50ms](https://medium.com/darklang/how-dark-deploys-code-in-50ms-771c6dd60671)