seratch's weblog in Japanese

About Scala, Java and Ruby programming in Japaense. If you need English information, go to http://blog.seratch.net/

2016 年の振り返り(仮面ライダー限定)

去年の大晦日、以下のようなエントリを書きました。需要があるかというとあんまりなさそうですが、今年の進捗を報告すべく、続編を書くことにしました。

seratch.hatenablog.jp

今年の息子との遊び

ガンバライジングは 2 月くらいまではやっていました。やらなくなった理由は、息子が IC カードを紛失するという失態をおかしてしまったためです。

f:id:seratch2:20161225014240j:plain:w600

夏は流行りにのって、ポケモン GO をそれなりにやっていたようです。電動アシスト自転車で息子と出かけては、公園などを巡ったりしていました。

f:id:seratch2:20161225014633p:plain:w400

ブットバソウルとは

bs.gashapon.jp

www.youtube.com

今年の 8 月から始まった新しいガシャポンゲームです。妖怪ウォッチをご存知の方であれば「おみくじ神社」「ドリームルーレット」と同じようなやつだと思っていただればと(そういう方がこのブログを読んでいるか謎ですが)。

  • 遊ぶこと自体は無料
  • お賽銭的にガシャポンで手に入れたメダルを登録すると一回遊べる、一度登録したメダルはもう使えない(ただし筐体単位)
  • ゲームで勝つと特別なガシャポンを回せる権利が得られ、激レアメダルがゲットできる

ゲームとしては、それほど難しくなくて

  • 敵の弱点に合わせたシリーズマーク・バトルタイプのメダルを 3 個選ぶ
  • 敵の弱点に合わせたエナジーアイテムというメダルを 1 個選ぶ
  • ボタン連打で敵と戦って勝利する
  • チャンスタイムを見守る

という流れでわかりやすいので(去年より大きくなったというのもありますが)このゲームに関しては完全に息子一人で勝手にやっています。

今年の戦果

メダル大集合

ライダーパワー 4,000 以上のメダル達です。メダルといっても基本的には妖怪メダルと同様、プラスティック製なのですが、ゲームに勝利してゲットした黄金のレアメダルだけは金属製になっていてずっしりと重たいです。

f:id:seratch2:20161225011928j:plain:w600

はじめてのレアメダル

初めてのレアメダル。8 月の開始当初なので 00 弾です。

f:id:seratch2:20161225012546j:plain:w600

これは白銀のレアメダルでなのでプラスティック製です。

http://bs.gashapon.jp/products/sp_medal.php

映画特典 5 点セット

こちらはこれは映画の前売り特典で入手したものです。

f:id:seratch2:20161225012322j:plain:w600

12/10 に公開された仮面ライダーの映画前売り特典です。

www.toei.co.jp www.movie-taisen.com

エナジーアイテム

これは 01 弾から登場したエナジーアイテムと呼ばれているものです。出た当初、うちはこれを持っていなくてチャンスタイムまで到達できないことが多々ありました。

f:id:seratch2:20161225011934j:plain:w600

カードバインダー

オフィシャルカードバインダーを使っています。

http://bs.gashapon.jp/products/binder.php

f:id:seratch2:20161230141033p:plain:w600

f:id:seratch2:20161225011938j:plain:w600

ただ、ちょっと収納しづらいのとボロボロになりやすいのが難点です。そこまでお金かけるつもりがないので買わないですが、ケースの方がいいんでしょうね。

www.amazon.co.jp

まとめ

ということで、これらのゲームについてご存知の方ならお分かりの通り、そこまで熱心にプレイしたわけでもないのですが、今年はポケモン GO とブットバソウルの年でした。

来年・・・そろそろ、友達と遊ぶことの方が多くなってくるだろうし、こういうのも来年までか、長くてもせいぜいあと 2 〜 3 年かもしれないですね。

macOS で「はがきデザインキット」を使った年賀状宛名印刷の手順

毎年、年賀状のためだけに Windows マシンを保全して年に一度 12 月だけ起動する *1ということをやっていたのですが、そのマシンもいよいよ退役となり、普段使っている MacBook Pro でスムーズに年賀状の宛名印刷をできないものかということで、今年やったことをメモしておきます。

使ったもの

使ったものは、これだけです。

Windows 用の別ソフトで使っていた宛名一覧をダンプした CSV ファイルが存在しているという状態だったので、ここから移行していきたいという状況です。

注意すべき点

作業手順としてはスプレッドシートで宛名一覧を編集して CSV に出力したものを「はがきデザインキット」に「住所読込」してから、プリンターで印刷という流れです。いくつか注意点があるので、書いておきます。

  • macOS の言語設定が日本語でないと「住所読込」「住所書出」が文字化けするので、普段、英語で使っていてもこの作業のときだけ OS の言語設定を日本語に戻す
  • 「住所書出」で出力する CSV ファイルは UTF-8 で出力できないので、一度試しに出力した後はスプレッドシートに読み込んだものをマスターデータにして「住所読込」のみで作業した方がよい
  • 「住所読込」で CSV ファイルの空行が無視されずに空の宛名として取り込まれてしまうので、CSV は空行がない状態で出力する
  • 敬称で「くん」を指定すると「住所読込」でエラーにならず、単に無視されるので、男の子は「君」づけにする
  • 「あて名面レイアウト」は事前に十分調整しないとダメ(郵便番号はデフォルトより少し下に下げる、他の項目も上下の幅を広げる、場所をずらすなどした方がよい)
  • 好みの問題ではあるが、フォントはデフォルト選択の明朝体より楷書体の方が私は良い気がした
  • 印刷時の「対象プリンタ」はデフォルト選択の「任意のプリンタ」ではなく、連携しているプリンタを選択する(そうしないと適切な「はがき」設定を選べない)

上記の点だけ注意すれば、あとは特にハマることはないかと思います。

手順

では、どのようにやったか手順をざっと紹介します。

はがきデザインキットをインストール

https://yu-bin.jp/create/design_kit/

この「インストール版」を選んで

f:id:seratch2:20161224211412p:plain:w500

「いますぐダウンロード」*2Adobe AIR が必要です。

http://yubin-nenga.jp/design_kit/install/

f:id:seratch2:20161224211529p:plain:w500

「あて名面作成」を選択

起動したら「あて名面作成」をクリックします。今回の手順では、はがきの面はすでに印刷済という前提なので、この機能しか使いません。

f:id:seratch2:20161224211849p:plain:w500

f:id:seratch2:20161224212414p:plain:w500

CSV の雛形を入手する

CSV として出力するためには 1 件以上のあて名を指定する必要があります。そのために、以下のように適当な内容であて名を 1 件追加して保存します。

f:id:seratch2:20161224212442p:plain:w500

f:id:seratch2:20161224212526p:plain:w500

f:id:seratch2:20161224212554p:plain:w500

「すべて追加」を押した後、「CSV 書出」を押すと保存ダイアログが表示されます。

f:id:seratch2:20161224213606p:plain:w500

デフォルトは「address_list.csv」ですが、好きな名前で保存します。

f:id:seratch2:20161224212639p:plain:w500

この address_list.csv を Numbers で開くと以下のように表示されるはずです。これをベースにコピーしていくとよいかと思います。

f:id:seratch2:20161224212650p:plain:w500

あて名を編集する

基本的には行を増やしていくだけですが、いくつかやってみて気づいた点を。

  • 「リスト表示用氏名」は「=A2 & " " & B2」としておくのが良さそう(人数が多いなら「連名1(姓名:自宅欄)」なども同様)
  • 最初の注意点にも書いた通り CSV 出力する前に空行は除去しておく方がよい

Numbers で作業する場合は、この「address_list.numbers」をマスターファイルとして保管しておくとよさそうです。

CSV 出力して「はがきデザインキット」に取り込む

Numbers の出力機能で CSV をつくります。

f:id:seratch2:20161224212722p:plain:w500

これを取り込みます。「はがきデザインキット」の方で柔軟に重複チェックをしてくれるわけではないので、CSV ファイルをマスターとして、読み込み済のものは全削除してから取り込むという流れでやるのがわかりやすいと思います。つまり、以下のスクリーンショットで赤く囲まれている「すべて選択」を押して「削除」した上で「住所読込」をします。

f:id:seratch2:20161224214134p:plain:w500

f:id:seratch2:20161224214258p:plain:w500

「差出人登録・あて名面設定」

「差出人登録・あて名面設定」で差出人情報とあて名面のレイアウト情報を調整します。

f:id:seratch2:20161224215619p:plain:w500

差出人情報を保存したら、次は以下の画面でフォント・レイアウトを調整します。

f:id:seratch2:20161224215551p:plain:w500

私は楷書体の方が好みだったので変更したのと、はがきの上に表示されている各エリアは拡大縮小・移動が自由にできるので、よしなに調整しました。特に差出人欄はデフォルトだと郵便番号欄にかかってしまっていたり、差出人の氏名が小さかったりするので必ず調整が必要です。このプレビューは印刷時とほとんどズレませんが、郵便番号は少し下に移動しておく方が綺麗に収まるかと思います(プリンタによってはまた違うかもしれませんが)。変更例は以下の通り。

f:id:seratch2:20161224215558p:plain:w500

いよいよ印刷

「差出人登録・あて名面設定」から差出人欄を設定した後、「すべて選択」して「あて名面の印刷」を押します。

f:id:seratch2:20161224220426p:plain:w500

以下のようにプレビューが表示されます。この時点でレイアウトを手直ししたくなったら「あて名面レイアウト一括設定」で再度修正します。

f:id:seratch2:20161224215604p:plain:w500

「印刷」を押していよいよ印刷に進みます。ここでデフォルト選択の「任意のプリンタ」ではなく、連携しているプリンタを選択してください。

f:id:seratch2:20161224220532p:plain:w500

「はがき」を選んで「年賀はがき」をプリンタにセットしたらいよいよ印刷です。(年賀状印刷をやっている方は釈迦に説法ですが)まず何度かはがき以外の紙に試し刷りして「あて名面レイアウト一括設定」で微調整を繰り返してから、実際にハガキに刷ると良いかと思います。

f:id:seratch2:20161224220537p:plain:w500

まとめ

ということで、お世話になっている方々へきれいな宛名印刷で年賀状を届けることができそうです。

「はがきデザインキット」は使いやすいソフトウェアなので、来年も使うだろうと思います。*3

ということで、少し早いですが 2016 年も大変お世話になりました。2017 年も引き続きよろしくお願い申し上げます。

*1:そして Windows Update を待つ...

*2:あなたと...

*3:2008 年から提供されていたようですが、情弱で試したことがありませんでした...

Skinny Framework Getting Started 日本語版

この記事は Scala福岡2016 - connpass でのハンズオン向けの入門記事です。

JDK (Java SE Development Kit) インストール

http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

Oracle 社の Web サイトにアクセスして、License Agreement に同意してから自分のプラットフォームにあったインストーラをダウンロードして実行してください。

f:id:seratch2:20160523212824p:plain:w500

インストール後はターミナルから java コマンドに PATH が通っていることを確認してください。java -version でエラーにならず以下のような出力が表示されれば OK です。

$ java -version
java version "1.8.0_71"
Java(TM) SE Runtime Environment (build 1.8.0_71-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.71-b15, mixed mode)
$

skinny ダウンロード

Windows / Linux の場合

https://github.com/skinny-framework/skinny-framework/releases/download/2.1.1/skinny-blank-app-with-deps.zip をダウンロードして解凍したディレクトリで skinny スクリプトを使って以降の作業をします。

http://skinny-framework.org/ にダウンロードボタンがあります。

f:id:seratch2:20160523213032p:plain:w500

Mac OS X の場合

Mac OS XHomebrew を使っているなら

brew update
brew install skinny

だけで OK です。Homebrew で始める場合は skinny new コマンドが使えます。

skinny new hello-skinny
cd hello-skinny

と実行してください。

Homebrew を使わない場合は Windows / Linux と同様、skinny-blank-app-with-deps.zip をダウンロードして解凍します。

これ以降の作業は全て共通です。

プロジェクトの動作確認

ここからは skinny スクリプトがあるディレクトリで作業します。Windowsコマンドプロンプトで作業する場合は ./skinnyskinny で読み替えてください。

$ ./skinny run

[info] Loading project definition from /Users/kazuhirosera/tmp/hello-skinny/project
[info] Set current project to skinny-blank-app-dev (in build file:/Users/kazuhirosera/tmp/hello-skinny/)
2016-05-23 21:45:31.340:INFO::pool-11-thread-3: Logging initialized @8585ms
2016-05-23 21:45:31.461:INFO:oejs.Server:pool-11-thread-3: jetty-9.2.17.v20160517
2016-05-23 21:45:31.858:INFO:oejw.StandardDescriptorProcessor:pool-11-thread-3: NO JSP Support for /, did not find org.eclipse.jetty.jsp.JettyJspServlet
2016-05-23 21:45:32.091  INFO   --- [ool-11-thread-3] skinny.micro.SkinnyListener              : The cycle class name from the config: Bootstrap
2016-05-23 21:45:32.260 DEBUG   --- [ool-11-thread-3] skinny.micro.SkinnyListener              : Loaded lifecycle class: class Bootstrap
2016-05-23 21:45:32.309  INFO   --- [ool-11-thread-3] skinny.micro.SkinnyListener              : Initializing life cycle class: Bootstrap
2016-05-23 21:45:32.739 DEBUG   --- [ool-11-thread-3] scalikejdbc.ConnectionPool$              : Registered connection pool : ConnectionPool(url:jdbc:h2:file:./db/development;MODE=PostgreSQL;AUTO_SERVER=TRUE, user:sa) using factory : <default>
2016-05-23 21:45:33.288:INFO:oejsh.ContextHandler:pool-11-thread-3: Started o.e.j.w.WebAppContext@77261de5{/,[file:/Users/kazuhirosera/tmp/hello-skinny/src/main/webapp/],AVAILABLE}
2016-05-23 21:45:33.310:INFO:oejs.ServerConnector:pool-11-thread-3: Started ServerConnector@62b55b27{HTTP/1.1}{0.0.0.0:8080}
2016-05-23 21:45:33.311:INFO:oejs.Server:pool-11-thread-3: Started @10556ms
[success] Total time: 2 s, completed May 23, 2016 9:45:33 PM
1. Waiting for source changes... (press enter to interrupt)

スタックトレースが出力されず 1. Waiting for source changes... (press enter to interrupt) で止まれば OK です。 この状態で http://localhost:8080/ で Web サーバ(Jetty)が立ち上がっています。停止させたい場合は Enter や Ctrl + C を押すとアプリが停止します。

それでは IntelliJ IDEA を使いたい人向けの解説を続けます。セットアップの必要ないエディタを使う方は読み飛ばしてください。Eclipse は筆者が Scala では使っておらずお勧めもできないため省略させていただきます。

ファイルの説明

http://skinny-framework.org/documentation/getting-started.html#project-structure

.
├── README.md # 自動生成された README です、プロジェクトに合わせて書き換えてください
├── bin
│   └── sbt-launch.jar # ./skinny や ./sbt が使う sbt の launcher です
├── build.sbt # これと project/Build.scala、project/plugins.sbt が sbt の設定ファイルです
├── project # sbt が使用するディレクトリです
│   ├── Build.scala # メインのビルド設定ファイルです
│   ├── build.properties # sbt 自体のバージョンを指定します、この記事時点で 0.13.11 が最新です
│   └── plugins.sbt # sbt プラグインを追加する場合はここに追加します
├── sbt      # ./skinny が使用する sbt 起動スクリプト
├── sbt.bat  # 同上、Windows 向け
├── skinny     # skinny スクリプト
├── skinny.bat #  同上、Windows 向け
├── src # Scala/Java のお作法的に src の下にソースコードや設定を置いていきます
│   ├── main # こちらが実アプリのディレクトリ
│   │   ├── resources # 設定ファイルなどを置く場所
│   │   │   ├── application.conf # アプリケーションの設定ファイルです
│   │   │   ├── logback.xml # skinny が使用する logback というログライブラリの設定ファイルです
│   │   │   └── messages.conf # 入力チェックエラーメッセージなどをここで指定します、i18n(国際化)対応
│   │   ├── scala # scala ソースコードの置き場所
│   │   │   ├── Bootstrap.scala # skinny アプリケーションが最初に呼び出すクラスです、名前は決め打ちです
│   │   │   ├── controller # controller を置く場所です、自由に変更してもコンパイルが通るなら問題ありません
│   │   │   │   ├── ApplicationController.scala # デフォルトの親 controller です、Ruby on Rails にならった命名ですが、リネームしても問題ありません
│   │   │   │   ├── Controllers.scala # ルーティングはここで指定してください
│   │   │   │   └── RootController.scala # http://localhost:8080/ はこの controller を呼び出します
│   │   │   ├── lib # util クラスなど置き場に困るようなコードはここに置いてください
│   │   │   ├── model # Rails でいう model としての置き場ですが、service や repository などが好みであれば変えても問題ありません
│   │   │   │   └── package.scala # デフォルトでこの package 全体で共有したいものがあればここに書きます
│   │   │   └── templates # Scalate というデフォルトのテンプレートエンジンが期待する package と class です
│   │   │       └── ScalatePackage.scala # Scalate の設定
│   │   └── webapp # Servlet の規約で置かれているディレクトリ
│   │       └── WEB-INF
│   │           ├── assets
│   │           │   ├── build.sbt # Scala.js 用の設定ファイルです、Scala.js を使わないなら不要です
│   │           │   ├── coffee # CoffeeScript を使って開発したい場合はここに *.coffee を置きます
│   │           │   ├── jsx    # React を使って開発したい場合はここに *.jsx を置きます
│   │           │   ├── less   # LESS を使って開発したい場合はここに *.less を置きます
│   │           │   ├── scala  # Scala.js を使って開発したい場合はここに *.coffee を置きます
│   │           │   └── scss   # LESS を使って開発したい場合はここに *.sass/scss を置きます
│   │           ├── layouts
│   │           │   └── default.ssp # デフォルトのレイアウトテンプレートです
│   │           ├── views
│   │           │   ├── error # HTTP ステータス 40x/50x のときに表示されるエラーページです、デフォルトでは ssp が使われます
│   │           │   │   ├── 403.html.jade
│   │           │   │   ├── 403.html.mustache
│   │           │   │   ├── 403.html.scaml
│   │           │   │   ├── 403.html.ssp
│   │           │   │   ├── 404.html.jade
│   │           │   │   ├── 404.html.mustache
│   │           │   │   ├── 404.html.scaml
│   │           │   │   ├── 404.html.ssp
│   │           │   │   ├── 406.html.jade
│   │           │   │   ├── 406.html.mustache
│   │           │   │   ├── 406.html.scaml
│   │           │   │   ├── 406.html.ssp
│   │           │   │   ├── 500.html.jade
│   │           │   │   ├── 500.html.mustache
│   │           │   │   ├── 500.html.scaml
│   │           │   │   ├── 500.html.ssp
│   │           │   │   ├── 503.html.jade
│   │           │   │   ├── 503.html.mustache
│   │           │   │   ├── 503.html.scaml
│   │           │   │   └── 503.html.ssp
│   │           │   └── root
│   │           │       └── index.html.ssp # RootController が render("/root/index") を呼び出していますが、このファイルが読み込まれます
│   │           └── web.xml # Servlet の設定ファイルです
│   └── test # テストコード、テスト用の設定ファイルの置き場です
│       ├── resources
│       │   ├── factories.conf # FactoryGirl を使った fixture 用のファイルです
│       │   └── logback.xml # テスト時に使用されるログ設定です
│       └── scala # テストソースコードの置き場です
│           ├── controller
│           │   └── RootControllerSpec.scala # MockController を使った controller のテストです
│           └── integrationtest
│               └── RootController_IntegrationTestSpec.scala # Jetty を起動した HTTP リクエストによるインテグレーションテストです
└── task
    └── src
        └── main
            └── scala
                └── TaskRunner.scala # db:migrate などのタスク実行設定がされているタスクランナーです

IntelliJ IDEA の設定

この説明は IntelliJ IDEA 2016.1.2 を前提としています。違うバージョンの場合、挙動が違う場合があるのでご注意ください。

まず Open を選んで、先ほど用意した skinny プロジェクトのディレクトリにアクセスします。

f:id:seratch2:20160523234750p:plain:w500

このようにディレクトリ自体が青色のアイコンになっていれば skinny プロジェクト(というより sbt プロジェクト)として認識されています。これ以降の手順を進めてください。

以下のスクリーンショットでは hello-skinny となっていますが、zip を解凍した方は skinny-blank-app となっていますので、読みかえてください。

もし普通のディレクトリのように肌色で表示されていたら、ターミナルから ./skinny idea を実行してから IntelliJ IDEA の Open を試してください(一度 IDEA を再起動してから Open を試した方がいいかもしれません)。

f:id:seratch2:20160523234813p:plain:w500

このように sbt プロジェクトとして import する設定があらわれます。デフォルトで OK ですので、このまま進めてください。

f:id:seratch2:20160523234823p:plain:w500

このように処理が始まるのでしばらく待ちます。

f:id:seratch2:20160523234833p:plain:w500

このように 4 つのプロジェクトを読み込むかどうか聞かれますが、このまま OK を押してください。

f:id:seratch2:20160523234846p:plain:w500

おそらく No Scala SDK in module と表示されていて、Scala ソースコードコンパイルエラー表示になっているかと思います。Setup Scala SDK というリンクから設定してください。

f:id:seratch2:20160523234907p:plain:w500

このようなダイアログで OK を押します。Scala SDK が未設定の場合は洗濯して設定します。このスクリーンショットでは 2.11.7 になっていますが 2.11.8 が選べるならその方が望ましいですが 2.11.x ならどれでも大丈夫です。

f:id:seratch2:20160523234918p:plain:w500

しばらく待って src/main/scala/controller/RootController.scala などをクリックして開いてみて赤いコンパイルエラー表示がなくなっていればセットアップ完了です。

f:id:seratch2:20160523234930p:plain:w500

設定がおかしくなったら

を試してみてください。

最初のコード生成

以下のページにならって最初のコードを自動生成してみましょう。

Getting Started - Skinny Framework

./skinny g scaffold members member name:String activated:Boolean luckyNumber:Option[Long] birthday:Option[LocalDate]
./skinny db:migrate
./skinny run

を実行するだけです。一つ一つのコマンドについて説明してきます。

$ ./skinny g scaffold members member name:String activated:Boolean luckyNumber:Option[Long] birthday:Option[LocalDate]

[info] Running TaskRunner generate:scaffold members member name:String activated:Boolean luckyNumber:Option[Long] birthday:Option[LocalDate]

 *** Skinny Generator Task ***

  "src/main/scala/controller/ApplicationController.scala" skipped.
  "src/main/scala/controller/MembersController.scala" created.
  "src/main/scala/controller/Controllers.scala" modified.
  "src/test/scala/controller/MembersControllerSpec.scala" created.
  "src/test/scala/integrationtest/MembersController_IntegrationTestSpec.scala" created.
  "src/test/resources/factories.conf" modified.
  "src/main/scala/model/Member.scala" created.
  "src/test/scala/model/MemberSpec.scala" created.
  "src/main/webapp/WEB-INF/views/members/_form.html.ssp" created.
  "src/main/webapp/WEB-INF/views/members/new.html.ssp" created.
  "src/main/webapp/WEB-INF/views/members/edit.html.ssp" created.
  "src/main/webapp/WEB-INF/views/members/index.html.ssp" created.
  "src/main/webapp/WEB-INF/views/members/show.html.ssp" created.
  "src/main/resources/messages.conf" modified.
  "src/main/resources/db/migration/V20160523235117__Create_members_table.sql" created.

[success] Total time: 8 s, completed May 23, 2016 11:51:17 PM

この時点で MVC のファイルが生成されて、ルーティング情報も設定済です。どのようになっているか skinny routes で確認してみましょう。:id は path パラメータで URL の一部が controller にパラメータとして渡されます。:id の値は後述の members テーブルの id です。:extjsonxml でアクセスできます。

GET  /?
GET /assets/css/*
GET /assets/js/*
GET /members
POST    /members
GET /members.:ext
POST    /members.:ext
GET /members/
POST    /members/
DELETE  /members/:id
GET /members/:id
PATCH   /members/:id
POST    /members/:id
PUT /members/:id
DELETE  /members/:id.:ext
GET /members/:id.:ext
PATCH   /members/:id.:ext
POST    /members/:id.:ext
PUT /members/:id.:ext
GET /members/:id/edit
GET /members/new

手順に戻ります。./skinny db:migrate でこのファイル DB に必要な members テーブルを作成します。

create table members (
  id bigserial not null primary key,
  name varchar(512) not null,
  activated boolean not null,
  lucky_number bigint,
  birthday date,
  created_at timestamp not null,
  updated_at timestamp not null
)

Skinny ではデフォルトでファイルベースのデータベースと連携するよう設定されていますが、MySQL などに変更も可能です。

$ ./skinny db:migrate

[info] Running TaskRunner db:migrate

2016-05-23 23:51:34.150 DEBUG   --- [     run-main-0] scalikejdbc.ConnectionPool$              : Registered connection pool : ConnectionPool(url:jdbc:h2:file:./db/development;MODE=PostgreSQL;AUTO_SERVER=TRUE, user:sa) using factory : <default>
2016-05-23 23:51:34.165  INFO   --- [     run-main-0] o.f.core.internal.util.VersionPrinter    : Flyway 4.0.1 by Boxfuse
2016-05-23 23:51:34.577  INFO   --- [     run-main-0] o.f.c.i.dbsupport.DbSupportFactory       : Database: jdbc:h2:file:./db/development (H2 1.4)
2016-05-23 23:51:34.722  INFO   --- [     run-main-0] o.f.core.internal.command.DbValidate     : Successfully validated 1 migration (execution time 00:00.020s)
2016-05-23 23:51:34.742  INFO   --- [     run-main-0] o.f.c.i.metadatatable.MetaDataTableImpl  : Creating Metadata table: "PUBLIC"."schema_version"
2016-05-23 23:51:34.766  INFO   --- [     run-main-0] o.f.core.internal.command.DbMigrate      : Current version of schema "PUBLIC": << Empty Schema >>
2016-05-23 23:51:34.766  INFO   --- [     run-main-0] o.f.core.internal.command.DbMigrate      : Migrating schema "PUBLIC" to version 20160523235117 - Create members table
2016-05-23 23:51:34.792  INFO   --- [     run-main-0] o.f.core.internal.command.DbMigrate      : Successfully applied 1 migration to schema "PUBLIC" (execution time 00:00.050s).
[success] Total time: 9 s, completed May 23, 2016 11:51:34 PM
$

ここまでできていれば ./skinny run を実行して 1. Waiting for source changes... (press enter to interrupt) が表示されたら、http://localhost:8080/members にアクセスしてみてください。このような CRUD 画面が自動生成されているはずです。

f:id:seratch2:20160528134757p:plain:w500

「New」ボタンを押すとこのように validation も設定済の入力画面が表示されます。

f:id:seratch2:20160523235553p:plain:w500

テストも自動生成されているので実行してみましょう。

./skinny db:migrate test
./skinny test

で、以下のように出力されます。

$ ./skinny test
[info] RootControllerSpec:
[info] RootController
[info] - shows top page
[info] MembersController_IntegrationTestSpec:
[info] - should show members
[info] - should show a member in detail
[info] - should show new entry form
[info] - should create a member
[info] - should show the edit form
[info] - should update a member
[info] - should delete a member
[info] RootController_IntegrationTestSpec:
[info] - should show top page
[info] MemberSpec:
[info] MembersControllerSpec:
[info] MembersController
[info]   shows members
[info]   - shows HTML response
[info]   - shows JSON response
[info]   shows a member
[info]   - shows HTML response
[info]   shows new resource input form
[info]   - shows HTML response
[info]   creates a member
[info]   - succeeds with valid parameters
[info]   - fails with invalid parameters
[info] - shows a resource edit input form
[info] - updates a member
[info] - destroys a member
[info] Run completed in 13 seconds, 149 milliseconds.
[info] Total number of tests run: 18
[info] Suites: completed 5, aborted 0
[info] Tests: succeeded 18, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[success] Total time: 23 s, completed May 23, 2016 11:58:23 PM

生成されたコードを理解する

Controller

Controller のコードは差分のみが実装された非常にシンプルなものになっているのでどうすればいいか戸惑うのではないかと思います。

// $ cat src/main/scala/controller/MembersController.scala
package controller

import skinny._
import skinny.validator._
import _root_.controller._
import model.Member

class MembersController extends SkinnyResource with ApplicationController {
  protectFromForgery()

  override def model = Member
  override def resourcesName = "members"
  override def resourceName = "member"

  override def resourcesBasePath = s"/${toSnakeCase(resourcesName)}"
  override def useSnakeCasedParamKeys = true

  override def viewsDirectoryPath = s"/${resourcesName}"

  override def createParams = Params(params).withDate("birthday")
  override def createForm = validation(createParams,
    paramKey("name") is required & maxLength(512),
    paramKey("lucky_number") is numeric & longValue,
    paramKey("birthday") is dateFormat
  )
  override def createFormStrongParameters = Seq(
    "name" -> ParamType.String,
    "activated" -> ParamType.Boolean,
    "lucky_number" -> ParamType.Long,
    "birthday" -> ParamType.LocalDate
  )

  override def updateParams = Params(params).withDate("birthday")
  override def updateForm = validation(updateParams,
    paramKey("name") is required & maxLength(512),
    paramKey("lucky_number") is numeric & longValue,
    paramKey("birthday") is dateFormat
  )
  override def updateFormStrongParameters = Seq(
    "name" -> ParamType.String,
    "activated" -> ParamType.Boolean,
    "lucky_number" -> ParamType.Long,
    "birthday" -> ParamType.LocalDate
  )

}

ベタに書いた Controller や SkinnyResource の実装を見てみてわからない点があれば私やチューター係の人に聞いてみてください。

ルーティング定義は src/main/scala/controller/Controllers.scala で有効になっています。ルーティング定義のサンプルはこの辺にあります。

Model

ここでいう Model は Ruby on Rails にならってデータベースアクセスが可能なモジュールというニュアンスです。実際に service レイヤーを設けて entity / DAO を分離して開発することもできますが Skinny のデフォルトのやり方は Ruby on Rails にならったこのスタイルです。データベースアクセスは以下のようにして REPL(Scala コードを実行する対話環境)で試してみましょう。

$ ./skinny console

REPL が起動したら、まずはデータが入っていない状態で全件取得してみましょう。

scala> Member.findAll()

  [SQL Execution]
   select m.id as i_on_m, m.name as n_on_m, m.activated as a_on_m, m.lucky_number as ln_on_m, m.birthday as b_on_m, m.created_at as ca_on_m, m.updated_at as ua_on_m from members m order by m.id; (0 ms)

  [Stack Trace]
    ...
    skinny.orm.feature.FinderFeatureWithId$class.findAll(FinderFeature.scala:57)
    model.Member$.findAll(Member.scala:17)
    ...

res1: List[model.Member] = List()

レコードを insert してみましょう。

scala> Member.createWithAttributes('name -> "Alice", 'activated -> false)

  [SQL Execution]
   insert into members (name, activated, created_at, updated_at) values ('Alice', false, '2016-05-24 00:17:34.008', '2016-05-24 00:17:34.008'); (0 ms)

  [Stack Trace]
    ...
    skinny.orm.feature.CRUDFeatureWithId$class.createWithNamedValues(CRUDFeature.scala:213)
    model.Member$.skinny$orm$feature$TimestampsFeatureWithId$$super$createWithNamedValues(Member.scala:17)
    skinny.orm.feature.TimestampsFeatureWithId$class.createWithNamedValues(TimestampsFeature.scala:24)
    model.Member$.createWithNamedValues(Member.scala:17)
    skinny.orm.feature.NoIdCUDFeature$class.createWithAttributes(NoIdCUDFeature.scala:122)
    model.Member$.skinny$orm$feature$CRUDFeatureWithId$$super$createWithAttributes(Member.scala:17)
    skinny.orm.feature.CRUDFeatureWithId$class.createWithAttributes(CRUDFeature.scala:277)
    model.Member$.createWithAttributes(Member.scala:17)
    ...

res3: Long = 2

この状態でレコード件数をカウントしてみます。1 件になっているはずです。

scala> Member.count()

  [SQL Execution]
   select count(1) from members; (4 ms)

  [Stack Trace]
    ...
    skinny.orm.feature.CalculationFeature$class.count(CalculationFeature.scala:30)
    model.Member$.count(Member.scala:17)
    ...

res5: Long = 1

このように where 句を指定することもできます。

scala> Member.where('name -> "Alice").where('activated -> false).apply()

  [SQL Execution]
   select m.id as i_on_m, m.name as n_on_m, m.activated as a_on_m, m.lucky_number as ln_on_m, m.birthday as b_on_m, m.created_at as ca_on_m, m.updated_at as ua_on_m from members m where m.name = 'Alice' and m.activated = false; (0 ms)

  [Stack Trace]
    ...
    skinny.orm.feature.QueryingFeatureWithId$EntitiesSelectOperationBuilder.apply(QueryingFeature.scala:326)
    ...

res8: List[model.Member] = List(Member(2,Alice,false,None,None,2016-05-24T00:17:34.008+09:00,2016-05-24T00:17:34.008+09:00))

より詳しい操作についてはドキュメントを参考にしてみてください。

ORM - Skinny Framework

View

表示する部分は上記のコマンドの場合、SSP (Scala Server Pages) で生成されています。JSP や Velocity に似たものでループや分岐など必要な処理を素直に書くことができます。

公式ドキュメントや Scalate のドキュメントを参照してください。

http://skinny-framework.org/documentation/view-templates.html

またこちらは Play Framework を使ったサンプルになりますが view template は認証ページなどのみにとどめてサーバから JSON のみを返して JavaScript で処理するようにしても良いでしょう。

https://github.com/skinny-framework/skinny-orm-in-play

やってみよう

TODO 管理アプリを作ってみる

task テーブルを設計して scaffold して TODO 管理アプリを scaffold してみましょう。JavaScript + JSON API の構成にして TodoMVC にしてもよいですね。

一応、こちらでサンプルをつくってみましたので、迷ったら参考にしてみてください。

GitHub - seratch/scala-fukuoka-hands-on-demo: Skinny Workshop at Scala 福岡 2016

Typetalk 連携のアプリを作ってみる

以下は今回の会場を提供してくださっているヌーラボ様の Typetalk の OAuth 2.0 と連携するサンプルアプリケーションです。

github.com

これをベースに Typetalk に投稿するアプリをつくったり、他のサービスでもログインできるようにしてみたりしてみてはどうでしょう?

see also: http://skinny-framework.org/documentation/oauth.htmlskinny-framework.org

Redmine のデータベースから reverse-scaffold してみる

以下は Redmine のデータベースから reverse scaffold してみた結果です。生成してから全く手を加えずにちゃんと動いています。

github.com

Skinny の reverse-scaffold は FK(外部キー)がない場合は勝手に association を生成しません。上記の model クラスに適切な belongsTo や hasMany を定義してみて ./skinny console で join クエリの動作を確認してみるのも良いでしょう。また、何か他の既存データベースをつかって生成してみてもよいでしょう。

Scala.js を試してみる

Skinny では ./skinny scalajs:watch を実行するだけで Scala.js を使った開発を始めることができます。Scala.js に興味がある方はこれを機にぜひ触ってみてください。

Assets Support - Skinny Framework

FAQ

  • java.net.BindException: Address already in use というエラーが出たら、すでに別の terminal で ./skinny run していないか確認してください
  • Unsupported major.minor version 51.0 のようなエラーは JDK のバージョンが古くないか java -version で確認してください

OSS Gateワークショップ 3/26 にメンターとして参加した #oss_gate

こちらのるびまを読んで、そういえばブログを書きましょうと話があったのをすっかり忘れて書いてなかったことに気づいたので先日の OSS Gate に参加したときのことを書いてみます。

Rubyist Magazine - Rubyist Hotlinks 【第 36 回】 須藤功平さん

私が参加したのは先日の 3/26 に開催されたOSS Gateワークショップの第二回です。半蔵門にあるコデアルさんのオフィスをお借りしての開催でした。

oss-gate.doorkeeper.jp

参加したきっかけは、知人の方が立ち上げから参加していて、興味を持ちそうな私を誘ってくれたことがきっかけです。最初に参加しようとしていた立ち上げミーティングには参加できなかったのですが、2 度目の正直ということで今回参加できました。

・・というところで、ちょっと色々と忙しくて、この記事を完成させる時間がなく、とりあえず Twitter でざっと発言しておいたのが以下。

私自身は色々と他にもやりたいこともあるので、深くコミットはできないかなと思っていますが、、できるだけ応援していきたいと思っています。これを読んで興味を持ってくれた方がいれば、ぜひ参加してみてください。

2015 年の振り返り(ガンバライジング限定)

このブログに書くか微妙なところですが、まあいいかと。

今年の 2 月くらいから 4 歳の息子とガンバライジングというアーケードゲームで遊んでいるので、それについて今年を総括してみます。 なお、本業については今年結構色々やっててまとめるの大変そうだし、特にやりませんw

ガンバライジングとの出会い

今年に入って Twitter の私の日本語アカウント(@seratch_ja)にちょくちょく仮面ライダーネタが出てくるようになりました。これでも自重してるんですが...

そもそも私と仮面ライダーについては以下のような感じ。

  • 子供生まれるまで平成仮面ライダーについて全く知らなかった
  • 子供とリアルタイムで見ているのは鎧武(ガイム)、ドライブ、ゴーストの 3 シリーズ

大人になってからもリアルタイムで仮面ライダーを追っている人は結構いますが、私は完全に息子の影響でした。

とはいえ、ガンバライジングについては最初は「アーケードゲームとかお金かかるし、カード集めてもねぇ」という感じだったのですが。

息子の仮面ライダーに対する異常なまでの情熱

うちの息子は 2 〜 3 歳の頃、数字などを教えてもどうにも興味を示さず、いつになったら数字をスムーズに言えるようになるの・・状態だったのですが、ふとあるとき、他のことだと数字に対するグダグダが嘘のように異常に覚えが良いことに気づきます。そう、それが仮面ライダーでした。

フリマで買ってきた昔の仮面ライダーの絵本や Hulu でたった一度見ただけのライダーも「これ何て書いてあるの?」といちいち聞いてきて、都度教えてあげるとそれをすぐに記憶しているようで、私が何度見ても覚えられないのを尻目に次からは「え、これはキバに決まってるじゃない」などと言ってきました。

そうこうしているうちに 3 歳も後半になってアンパンマンをそろそろ卒業かなというタイミングで、二人で出かけていたときに買ったマクドナルドのハッピーセットにガンバライジングカードが付いていたのです。

http://www.ganbarizing.com/event/mcdonald.htmlwww.ganbarizing.com

そういえば、このショッピングセンターに筐体があったなぁと思い、息子の仮面ライダー熱のこともあり、試しにやってみたのが始まりでした。そして、まんまと戦略に・・

ガンバライジングの遊び方

ゲームセンターに行くとポケモン妖怪ウォッチドラゴンボールなどカードバトル系のアーケードゲームで子供達がたくさん遊んでいるのを見かけることがあるかと思いますが、ガンバライジングはその仮面ライダー版です。

妖怪ウォッチドラゴンボールほどは人気がないらしく、うちの近所だと基本的には並ばずに遊べる点が大人としてはありがたいです(アキヨドなどもっと人の多いところではそれなりに並んだりします)。

どういうものかはこの辺を見ると全部書いてあるのですが

私なりに前提知識がない人向けにざっくり書くと

  • 100 円を入れると 1 回遊べる + ランダムでライダーカードが 1 枚出てくる
  • ライダーカード 1 枚につき 1 人の仮面ライダーがゲーム内にロードされる
  • 3 枚のカードをロードして 3 対 3 のストリートファイト的な戦いをする
  • 戦いはスロットマシンで 〜100 までの攻撃力を 3 人分確定させて合計値(+エフェクト)で争う
  • ゲージがたまるとライダーカードを裏返せるイベント(バースト)が発生し、そのライダーがパワーアップする
  • IC カードを読み込ませて経験値やアビリティを蓄積してくとだんだん強くなっていく
  • 仮面ライダーゴーストからは変身ベルトで使うゴーストアイコンというおもちゃとも連動するようになった(これでちょっとプレイする子供が増えた気がします)

という感じです。ルールは比較的シンプルなので 3 歳児にも遊びやすかったようです。ただ本来は 3 歳でやってる子はそんなにいなくて、おそらく文字がある程度読める幼稚園から小学生がターゲットかなという内容です。

ガンバライジングカードの見方

現在放映中の仮面ライダーは「仮面ライダーゴースト」ですが、ガンバライジングでは放映中のライダーだけでなく過去の仮面ライダーのカードも出てくるようになっています。

公式サイトのカード一覧を見ると、どう見ればいいのか一瞬戸惑うかもしれませんが、とりあえずは「レアリティ」を見ればよいです。

例えば「LR」は「Legend Rare(レジェンドレア)」の略で、現行バージョンではもっともレア度が高いカードです。基本的にレア度の高いカードはカードバドルの中でも強いカードとして機能します。

カードのレアリティはカードの右下に「LR」などの略称が記載されているので現物を見るとすぐにわかるようになっています。カードショップで買い物するときなどは、レアリティとそのカードがどのシリーズのものかを見るとよいでしょう。例えば、現行の「バッチリカイガン 2 弾」だと「K2」となっていて、その前の仮面ライダードライブ時代の「ナイスドライブ {1-6} 弾」シリーズでは「D6」のように表記されています。

今年のプレイを振り返る

今年、私は息子と 150 回程度ガンバライジングをプレイしました。

1 回につきカードは最大 5 枚まで買える仕組みになっていますが、新しいシリーズが始まったときはたまに多めに買ったりする程度にとどめ、基本的には 1 枚だけ買って 2 回プレイするという形でした。

また、ガンバライジングは一度のプレイ時間が長いのが特徴で、オンライン対戦*1だと 10 分を超えることも珍しくありません。

これらの理由から、たとえ大人がハマっても大金を使うことが非常に難しい点がよいと思います。 11 ヶ月で 150 回なので、課金した金額は月 2000 円満たない程度といってよいでしょう。

高いか安いかは人によって判断分かれそうですが、子供とだいぶ楽しく遊んだので高くはないかなと・・たぶん。

LR/CP/VR カード

誰得かつガチ勢の人が見たら鼻で笑われそうなカードリストですが、入手したカードを棚卸ししてみました。

カードショップでも多少は買いましたが、基本的には上記のプレイの中で入手したものです。レジェンドレアは真ん中の「仮面ライダーゴースト ムサシ魂(K1-007)」だけで、あとは CP(キャンペーン)、VR(バーサスレア)です。

f:id:seratch2:20151231144438j:plain:w800

バースト面はこんな感じ。

f:id:seratch2:20151231144444j:plain:w800

個人的には魔進チェイサーがフォトジェニックなので好きですね。

SR カード

ちょっと上記だけだと寂しかったので、その下のグレードである SR(スーパーレア)のカードから一部をピックアップしてみました。

この SR 程度のカードであればカードショップに行けば 100 円で買えたりしますので、子供とガンバライジング始めたけどいいカードがなかなか出ないなという方は一度カードショップに行ってみるとよいのではないでしょうか。

f:id:seratch2:20151231144456j:plain:w800

ちなみにカードショップは色々回ったわけではないですが、正直他のカードゲームほど在庫を持っているお店が多くないのが現状です。

私が行った中で一番良かったのは中野ブロードウェイの「まんだらけカード館」さんでした。ここにはかなり多くのカードがそろっています。

http://www.nbw.jp/nbwcgi/shops/detail/157/backurl:@nbwcgi@shops@index@kana:@category%5B0%5D:HOBBY@floor%5B0%5D:2F@page:2

その他買ったもの

まずガンバライジングを始めるなら IC カードを買いましょう。いろいろ種類がありますが、私は緑色のやつを使っています。まだまだ 400 回のセーブ回数に達しないので、一枚目です。

http://www.ganbarizing.com/play/about-ic.php

ガンバライジングでは、プレイ中にカードをこすったり裏返したりするので、無防備な状態で扱っているとすぐにカードが擦り傷だらけになってしまいます。レアなカードだけでも保護フィルムに入れてあげましょう。

http://www.yodobashi.com/ec/product/100000001001014832/index.html?gad1=&gad2=g&gad3=&gad4=56278881131&gad5=7419906215107049486&gad6=1o2&xfr=pla&gclid=CP-gg4y9hcoCFVgkvQodKsIKmA

カードが増えてくると、すぐに取り出せるようにカードバインダーに整理して入れてあげる必要も出てきます。私はもっと安いやつにしていますが、純正のやつはカッコいいですね。

http://www.amazon.co.jp/gp/aw/d/B012CT49N0/

ちなみにカードバインダーの中のページは買い足せばどんどん増やしていけるのですが、4 穴式と 6 穴式という互換性のない二つの製品があるので買い間違えないように注意しましょう。私は最初に買ったとき、そんなトラップがあるとは思わず、まんまと間違えました。

よく間違える人がいるらしく、親切な店員さんであれば 4 穴だけど合ってる?と聞いてくれたりします。

まとめ

ということで、ガンバライジング限定で私の 2015 年を振り返ってみました。

もし興味がある人がいましたら、カンファレンスやミートアップイベントなどでお会いしたときにでもガンバライジング談義を持ちかけてくださいw

まあ来年も今年ほどやるかというと他のことにもっと時間使わないといけないなと思ってますが、、息子が飽きないうちはある程度は付き合ってあげようかなと*2

*1:ちなみに、このオンライン対戦は本当にリアルタイムで対戦しているわけではなく、同時間帯にオンライン対戦に参加しているプレイヤーのデータを使ったコンピュータとの戦いです。同じ場所に筐体が 2 台あって連携し合っていればその場でリアルタイム対戦もできます。

*2:建前的には私は付き合ってあげているのです

Skinny Meetup Tokyo 2 を開催しました #skinnyjp

Skinny Framework 2.0 をリリースして一ヶ月弱、@yusuke さんのご厚意により、東池袋サムライズムのオフィスをお借りして Skinny Meetup Tokyo の第 2 回を開催させていただきました。

skinnyjp.doorkeeper.jp

当日使ったスライドはこちら。

www.slideshare.net

英語版はこちら。

www.slideshare.net

関連する tweetTogetter にまとめました。

togetter.com

当日の内容

Meetup の流れは、まず、私の方から Skinny が 2.0 で変わったこと(とちょっとだけさだまさしコンパイラのデモ)をお話しました。次に、社内の情報共有ツールの実装に Skinny Framework を使ってくださっているという @roundrop さんから、その社内情報共有ツールについての紹介、初めての Scala 開発で Skinny Framework を使ってどうだったかという所感についてお話いただきました。具体的には以下のインタビューで触れられている Siita というツールです。

www.atware.co.jp

数年 Scala をやっている身からするとすっかり忘れかけていたような、初めて Scala をやったときに困った点などもバランスよくまとめていただいていたので、おそらくこれから Scala、Skinny をやってみようという方々に大変参考になったのではないかと思います。この発表のスライドは後日公開いただけるとのことでしたので、楽しみにしております。 (追記)公開していただいたので、以下に埋め込みました。

www.slideshare.net

サムライズム最高

当初は一人千円いただいてピザとドリンクを準備予定でしたが、サムライズム @yusuke さんのご厚意に甘えさせていただきまして、なんと無料で懇親会を行うことができました。再度、お礼申し上げる次第です。

tweet とこのブログで紹介させていただく程度のことしかできませんが、以下のようにサムライズムでは OSS コミュニティも応援されているそうです。また IntelliJ IDEA や JRebel の業務導入を検討されている企業様におかれましては、ぜひ日本の商慣行にも柔軟に対応しているサムライズム社でご購入いただければと思います!

Skinny Micro

今回、初めて Skinny Micro についてちゃんと説明させていただきましたが、Scalatra を fork してリファクタリング、機能追加したものでかなり手軽で使いやすいライブラリになったのではないかと思っています。

Skinny Micro

どれくらい手軽かというと、以下に示すこれだけのコードで Web アプリをつくれるくらい手軽です。この Web アプリは Jetty サーバで起動して curl -v 'localhost:4567/say-hello?name=Martin' というリクエストに対して Hello, Martin! というレスポンスボディを返します。

https://github.com/skinny-framework/skinny-micro/tree/master/scalas-samples

#!/usr/bin/env scalas
// or ./scalas Hello.scala
/***
scalaVersion := "2.11.7"
libraryDependencies += "org.skinny-framework" %% "skinny-micro-server" % "1.0.0"
*/
import skinny.micro._
object HelloApp extends WebApp {
  get("/say-hello") {
    s"Hello, ${params.getOrElse("name", "Anonymous")}!\n"
  }
}
WebServer.mount(HelloApp).port(4567).start()

Heroku にすぐにデプロイできるサンプルや基本的な使い方を列挙したサンプルもありますので、ご参照いただければと思います。

https://github.com/skinny-framework/skinny-micro-usage-example

https://github.com/skinny-framework/skinny-micro-heroku-example

まだ公開して日が浅く GitHub スター数がちょっと少なめなので、気に入った方はぜひ stargazer になっていただけると嬉しいです。

github.com

Skinny の今後

Skinny Framework

Skinny 2 は大きな非互換を入れたわけでなく Scalatra からの移行という大きなイベントがあったのでメジャーバージョンを上げたという事情がありました。既に 1.3 でフレームワーク本体で備えるべき機能はそれなりに揃ってきているという認識で、大きくコードベースを変えていくことは考えていません。しかし、当然ながらソフトウェアに完成ということはありませんし、また利用者からするとメンテナンスされ続けていることは非常に重要なことですので、これからも手を入れ続け、マイナーバージョンでのリリースは続けていきます。

Skinny Framework の売りとしては、以下のような内容に共感いただける現場・用途には非常にマッチすると考えています。改めて明文化してみましたが、これは公式サイトにも明記しておくべきですね。

  • 今後も Scala 界における Servlet での Web アプリケーション開発フレームワークデファクトを目指し続けます
  • 今後も(既にコモディティ化している)Rails のイディオムや基本的なコンセプトに近い立場を保つことで、その下地がある開発者にとって敷居の低いフレームワークであり続けます
  • 既に 1.3 で当初予定していた最低限の機能セットは実現できたと考えており、安定フェーズとしてプロジェクトを運営していきます
  • 外的要因(Scala 本体など)の大きな変化以外での非互換な変更は基本的に入れない方針で運営していきます
  • Servlet に依存していないサブモジュール(ORM や Validator、HTTP クライアントなど)は今後も独立したライブラリとして利用可能であることを保証し続けます
  • 日本語圏に閉じず、世界中のさらなるユーザ拡大に努めてガラパゴス化のリスクを避ける取り組みを今後も続けます

特に、運用に入ってからのメンテコストを抑えたい、新しいメンバのキャッチアップのしやすさを重視したいという目的の場合、期待に答えられるフレームワークだと思っておりますので、選択肢の一つとしてご検討いただければと思います。

まだ時期やプランの詳細は未定なのですが、来年は Skinny Framework を業務の現場で利用いただきやすくなるようなサポートにもチャレンジできないかと検討しているところですので、引き続きよろしくお願いいたします。

ScalikeJDBC / Skinny Framework グッズ 2015 春モデル

SUZURI 最高

去年から GMO ペパボさんの suzuri.jp を利用して Skinny Framework のロゴをプリントしたマグカップを販売しています。

これまでに 13 個お買い上げいただいております。ありがとうございます!*1

Skinny Framework 2015 Spring

さて、春ですし 2015 春モデルと称して新しく T シャツもつくってみました。

お子さんが生まれた方はぜひロンパースを。

暖かくなってきたので時期的にちょっと微妙ですが、スウェットもつくってみました。

ScalikeJDBC 2015 Spring

待望の? ScalikeJDBC グッズもつくりました。ScalikeJDBC を使って開発されている方もどうぞ。

みんなで買えば送料がお得

販売しているグッズ一覧はこちらで見ることができます。

https://suzuri.jp/seratch

複数口で買うと送料がお得になります。お買い上げいただける際はぜひ開発チーム、部署、会社単位でまとめてご注文ください!

*1:トリブンは 0 円設定なので、私の懐には 1 円も入れておりませんが