Weblog by shuuji3

Software Engineering

Play Framework using Scala

この記事では、テキサスのTrynity Universityの教授Mark C. LewisさんがYouTubeで公開している「Play Framework using Scala」をハンズオンで進めながら、やったことや理解したことなどをメモしています。

Mark Lewisさんは、スーパーコンピュータなどで天文学のシミュレーションなどをしているそうです。Scalaを使ったプログラミングやウェブ開発やビッグデータ処理の講義をしていて、授業前に学生が見るビデオをYouTubeで公開してくれています。

私が知ったきっかけは、LightbendのPodcastの「Teaching Scala To Computer Science 101 Students | @lightbend」というエピソードです。CS 101の動画だけでなく、Play Frameworkの動画があることを知りました。前からPlay Frameworkは気になっていて知りたかったので、見てみることにしました。

01. Playlist Introduction

公式サイトの確認とThe Reactive Manifesto

  • はじめに公式サイトを見ました。
  • 一番の特徴はReactiveであることだと言います。これは、The Reactive Manifestoの考えに基づいています。
    • Note: アジャイルマニフェストのようなThe Reactive Manifestoというものがあることを初めて知りました。日本語翻訳もあります。応答性に優れた分散システムの特徴について説明したもののようです。要約すると次のように説明できます。
      • 優れた分散システムは、メッセージ駆動をベースとし、大量の要求に対してelastic(scalable)であるべきであり、障害に対してresilientであるべきである。その結果、responsiveという価値を実現することができる。
      • Note: 全体的に主張していることが、今読んでいる「Designing Data-Intensive Applications」での議論に非常に近い気がしました。

ビルディングブロック Akka HTTP

  • Play Frameworkビルディングブロックとして、 Scalaの非同期ウェブサーバーのライブラリAkka HTTPを利用している。

02. Structure of our Play Project

プロジェクトのインポート

  • Mark Lewisさんが用意したPlay-VideoとよばれるPlayのプロジェクトを使用します。
  • はじめに、ビデオではEclipseでプロジェクトをimportしています。
    • Server、Client、Shareのコンポーネントからなるプロジェクトです。Eclipseでは、4つのコンポーネントが認識されているため、1つを除外する必要があります
      • Note: 私はいつも使っているIntelliJ IDEAでGitHubのリポジトリのURLからプロジェクトをロードしました。この場合は、正しく3つのコンポーネントが認識されました。
      • Note: IntelliJ IDEAでScalaの開発をするときに素晴らしいところは、project.sbtの存在から自動的にsbtプロジェクトであることを認識してくれることです。そして、プロジェクトにふさわしい適正なバージョンのScalaとsbtをインストールしてくれ、依存関係のライブラリもivyを使って自動的にインストールしてくれます。素晴らしいです。
      • Note: ただし、今回のプロジェクトでは初期セットアップに結構時間がかかりました。完了までに9 min 42 secかかりました。

ディレクトリ構成の確認

  • プロジェクトをロードしたら、まずは、serverディレクトリを概観します。このディレクトリには次のように4つのディレクトリが存在します。重要なものだけ見ていきます。
    • app/: MVCフレームワークのコントローラーとビューに相当するファイルが格納されています。
    • conf/:
      • application.conf: アプリケーション全体の設定ファイルです。
        • Note: 私は設定ファイルが同じような名前のRuby on Railsを思い出しました。
      • routes: ルーターが定義されています。ルーターでは、HTTPのメソッド・パスのペアからコントローラーへのマッピングが定義されます。
    • public/: 静的ファイルが配置されます。
    • test/: テストを書いたSpecファイルが格納されています。
      • Note: play.api.test というライブラリがimportされています。Playは内部に専用の便利なテスト用ライブラリを持っているようです。

サーバーの起動と静的ファイルの表示

  • サーバーを起動する
    • サーバーを起動するには、sbt runを実行します。ビデオでは、sbtでインタラクティブシェルの世界に入り、その中でrunコマンドを実行しています。
    • localhost:9000でサーバーが起動します。
    • Note: DjangoやRuby on Railsでは、ふつう、開発専用のサーバーが起動します。このサーバーも開発用のものなのでしょうか? ルーティングできないページを表示すると、routerのregexリストが表示されたので、やはりそのようです。
  • ルーターの設定を確認する
    • conf/routesファイルを確認すると、GET /assets/*file controllers.Assets.at(file)という定義があります。これが静的ファイルの配信を定義しているルートです。
      • Note: *fileは変数を定義していて、コントローラーハンドラに渡せるようになっているみたいですね。
  • ブラウザで確認する
    • public/ディレクトリにある静的ファイルを表示します。
    • http://localhost:9000/assets/basicStuff.html を開くと、「This is a basic HTML file.」と表示されました。実際に、public/basicStuff.htmlがサーバーから配信されました!

03. Making Our First Page with Play using Scala

index viewの確認

index.scala.htmlは次のように定義されています。

@(message: String)

@main("Play with Scala.js") {
<h2>Play and Scala.js share a same message</h2>

<ul>
  <li>Play shouts out: <em>@message</em></li>
...
}

viewの1行目はパラメータを指定しています。ここでは1つのStringを指定しています。

テンプレート内では、@messageのように、@プリフィックスを付けて変数を参照できます。普通のテンプレートエンジンですね。

面白いのは、@mainです。同じディレクトリにある以下のようなmain.scala.htmlを、2つの引数を渡して呼び出しています。

@(title: String)(content: Html)

<!DOCTYPE html>

<html>
  <head>
    <title>@title</title>
...
  <body>
    @content
...

1行目にパラメータが2つ定義されています。1つの括弧内に2つのパラメータを並べるのではなく、カリー化を使用して2つの括弧で2階の関数のように定義されています。ユニークで面白いです。

2つ目の引数には、{}で包んだHTMLが渡されていました。この構文は、Play Framefork内でHtml型のオプジェクトに変換する糖衣構文として実装されているような気がします。変数と同じように埋め込むと、有効なHTMLとして展開されるようです。これも面白いです。

新しいコントローラーTaskList1の作成

次のようなファイルを作成して、TaskList1というコントローラーを作成しました。

package controllers

import javax.inject._

import play.api.mvc._
import play.api.i18n._

@Singleton
class TaskList1  @Inject()(cc: ControllerComponents) extends AbstractController(cc) {
  def taskList = Action {
    Ok("This works!")
  }
}

依存性の注入(Dependency Injection)

@Singletonは依存性注入のために必要なデコレーターらしいです。

javax.injectライブラリをimportして、インジェクションを行えるようにしています。AbstractControllerにccを注入して、これを継承したTaskList1という新しいコントローラーを定義しています。

Note: 私は依存性の注入(DI)を活用するフレームワークを使った経験がAngularで少し触れた程度しかないので、雰囲気が少しわかるという程度の理解しかありません。もっと学習が必要です。

Actionの定義とヘルパー関数TODOの活用

次に、Actionを定義します。Actionは、routerでルートの3列目に定義されていた関数です。ここで、ルートからパラメータを受け取れます。

play.api.mvc.TODOというヘルパー関数があり、実装前のActionの代わりにdef taskList = TODOのように指定できます。こうすると、ページにアクセスしたときに未実装であることを示すTODOページが表示されます。便利です。

TODOをAction { Ok("This works!") }で置き換えると、HTTP 200 OKのステータスを持ち、Bodyが文字列This works!であるようなHTTPレスポンスが返されます。

次のビデオでは、単純な文字列だけでなく、viewを作成していきます。