🦕

Deno と Fresh でコンペのランキングシステムを作った話

2022/12/25に公開
2

こんにちは。株式会社アイデミーの清水(@meso)です。

アイデミーは、DXリテラシーからAI/機械学習の専門知識までオンラインで学べるラーニングサービス Aidemy を運営しています。

機械学習の学習をしているお客様から、実際に学んだ知識を活かして機械学習モデルを作ってみたいが、手元に良いデータがないため学んだ知識を活用したり研鑽したりする機会に乏しいため、そういう機会が欲しい、というご意見をお伺いすることが度々ありました。
そういったお声に応えるべく、Aidemy Business のお客様に参加社を限定したワンデーコンペ「Comp8」を開催しました。

その Comp8 で用いたランキングシステムを Deno と Fresh を用いて開発したため、そこで得た知見をシェアしようと思います。

What is Comp8

Comp8 は「こんぺいとー」と読み、8 時間で完結する コンペ というところからその名が付けられました。有名なデータ分析のコンペだと、代表として Kaggle がありますが、開催期間が長期間のものが多くモチベーションを保つのが大変だったり、長期間に渡って業務時間(またはプライベート時間)を割くことができないなどの事情がある方も多いという難点があります。そのため、参加のハードルを下げ、他コンペとの差別化をするという意味でも1日完結型のコンペを開催してみようということになり、誕生しました。

アイデミーには Kaggle 等にも積極的に参加しているデータサイエンティストも在籍しているため、コンペとはどういうものかというのはよく理解はしていましたが、コンペを主催する経験というのはこれまでありませんでした。

そのため、ランキングシステム(いわゆる Leaderboard と呼ばれるもの)についても、既存のものがあるわけでもなくゼロから自分たちで用意する必要がありました。Kaggle には自分たちのオリジナルのコンペを開催するセットが用意されてたり、OSS でも Leaderboard 的なものはいくつかありはしたのですが、今回の用途には上手くフィットしなかったりしたので、自分たちで開発することにしました。

Deno と Fresh

開発する際には、まず技術選定をします。アイデミーは機械学習周り以外にはおいては TypeScript を第一の選択とする会社なので、言語はTypeScript でいくことにしました。その上で、Node でいくか Deno でいくか Cloudflare などの CDN エッジランタイムでいくか、という選択肢がありましたが、今回はまだ使ったことがない技術を試すチャンスということもあり、Deno を選択しました。

Deno とはなにか、ということはここには書きませんが、僕は初期からの Node.js のファンであり、それはすなわち Ryan Dahl のファンであるということですので、もちろん Deno にもとても注目をしています。

そして、フレームワークとしては Fresh を採用することにしました。Deno のフレームワークはいくつかあり、また最近 Node との互換性も高まっているので、Node 用のフレームワークも使えるようになってきてはいるのですが、やはり何より Deno 本家が推してる(開発してる)フレームワークということで、まずはこれを使って見ないとだめだろうということで、Fresh にしました。また、デプロイ先も、素直に Deno Deploy を用いることにしました。

参加者は CSV ファイルを提出し、それを採点した結果をランキング形式で表示する、というのが要件です。参加チームにはそれぞれ EC2 のインスタンスが割り振られており、その EC2 から S3 に CSV ファイルがアップロードされ、アップロードを契機に Lambda が発火して採点し、採点結果が DynamoDB に保存されるので、その DynamoDB に Deno Deploy からアクセスして見に行って、結果を表示するというのが全体の処理の流れになります。

Deno と Fresh の書き味

Fresh のバージョンは 1.1.2 を使ったため、それより新しかったり古かったりすると、使い勝手は異なってる可能性はあります。書き味でいうと1.1で大きな改善があったため、少なくともそれ以降を使うといいでしょう。

ビルド不要

一番の特徴はなんと言っても、ビルドが不要なことでしょう。コード書いてビルドせずにそのまま実行して結果を確認できるというのは、(多くのフレームワーク等が自動再ビルド&ブラウザの再リロードなどの仕組みを備えていることを踏まえた上でも)やはり開発のテンポが1段あがります。

そして、ビルドが不要ということはすなわち、ビルドのために必要な設定ファイルが不要ということでもあります。この設定ファイルレス(実際には自動で作られてほとんど触る必要のない設定ファイルや、ライブラリのバージョンを一括管理するための設定ファイルはあります)というのも、Fresh の歓迎すべき特徴だと思います。

開発環境と本番環境で実行ファイルが異なる

開発環境では deno task start で Fresh のサーバーを起動しますが、その際に呼ばれるのは dev.ts というファイルになります。本番環境である Deno Deploy では、デフォルトで main.ts が呼ばれることなります。

この違いがあるおかげで、開発環境でしか使わないライブラリは dev.ts で呼び出せばよくなり、環境の違いを設定ファイルに切り出さずにコードで表現できるという意味で、とても優れたやり方だと思いました。

環境変数の使い分けに便利

実際に、ローカルの開発環境では .env に書かれた環境変数を使い、本番環境では Deno Deploy のコンソール上で設定された環境変数を使う、というのはとてもよくあるケースだと思います。その場合、.env ファイルを用意した上で、dev.ts に以下の行を足すだけで、やりたいことが実現できます。

dev.ts
import "dotenv/load.ts";

Deno には、ビルトインで .env から環境変数を読み込む仕組みが用意されているので、それを呼び出すだけです。後は使いたいところで

const SECRET_KEY = Deno.env.get("SECRET_KEY");

のようにするだけで、開発環境であれば(すなわち dev.ts から起動され、dotenv/load.ts を読み込んでいれば).env ファイルに書かれた環境変数を読み込みますし、本番環境であれば Deno Deploy のコンソールで設定された環境変数を読み込みます。

React 用のライブラリを使う

そんな感じでほとんど詰まることもなく、快適に開発を進められていた矢先に、チームごとのスコアの推移をグラフで見られるようにしたいという話になりました。

Fresh が使ってるのは React じゃなくて Preact ですが、まあ React との互換レイヤーもあるし、いけるんじゃねってことでグラフ表示には React 用のライブラリである Recharts を使うことにしました。

Preact のドキュメントでは、互換レイヤーである preact-compatreact のエイリアスに設定すればいい的なことが書かれてるんですが、例に挙げられてるのが webpack などのビルドツールを使用する場合のやり方ばかりで、Deno の場合にどうすればいいかは書かれていませんでした。

色々調べた結果、ESM Module を配信している esm.sh にエイリアスの書き方が書かれていたため、それを参考に import_map.json に以下のように記述したところ動かすことに成功しました。

import_map.json
{
  "imports": {
    //...略
    "recharts": "https://esm.sh/recharts@2.1.16?alias=react:preact/compat&external=preact/compat"
  }
}

外部ライブラリとして preact/compat を利用し、さらに preact/compat にはエイリアスとして react を用いる、という意味だと思います。

注意点としては、グラフのライブラリなどはクライアントサイドで JavaScript を用いるので、Fresh のルールではそういったコンポーネントは islands フォルダ配下に置く必要がある点です。そうしないと、マウスポインターの位置に合わせて表示を変えるようなインタラクティブな動作はできません。

Deno Deploy まわり

Deploy に関しても、GitHub のリポジトリと紐付けしちゃえば、あとは push すれば更新されるという極めてシンプルな構成になっており、迷うようなところもありませんでした。また、今回の使い方であれば、完全に無料枠の中で収めることができました。

まとめ

Deno のビルトイン TypeScript の便利さと、Preact と Twind を(ReactとTailwindの代わりに)使った Fresh の書き味の良さが上手く融合されて、開発体験としてはとても良かったです。今回はイベント用という一発ものでの採用でしたが、今後はサービス開発などにも利用していきたいなと思えるほどでした。

というわけで、Deno や Fresh を使った開発もするかもしれない TypeScript の会社アイデミーに興味がある方は、是非お気軽にお声がけください!

https://aidemy.co.jp/recruit/

Aidemy Tech Blog

Discussion