next HTML

w3cのwikiに、次世代HTMLのアイデアリストがまとめられているのを眺めてみました。
http://www.w3.org/wiki/HTML/next

面白いのがいくつかあったのでピックアップしてみます。

Advanced Anchors

<a href="w3.org/page.html$section>div>p"> go there </a>

おそらく「そのページのsection > div > pへのアンカー」という意図のURLで、CSSセレクタでアンカー指定できるようにするアイデアですね。
アンカーIDが振られていないページなどへのリンクに使えそうです。

ComboBox

<select name="age" inputable="inputable">
<option value="11"></option>
<option value="12"></option>
</select>

自由入力できるプルダウン、コンボボックス。ローカルアプリケーションでは一般的に使えるのに、むしろなぜ実装されていないのか。
確かに欲しいですね。JSとCSSで頑張って実装しているケースが多いですが、ブラウザでサポートしてくれるのがやっぱり一番安心。

おまけ

目次化されていませんでしたが、目を引いたので。

BR
{
   breakline:right;
}

breakline: none | left | right  ;
none : = default
left : = insert a breakline before the element
right : = insert a breakline after the element

近年で、HTMLタグは文章を意味づけするものであり、
スタイルを適用するものではないという考え方が大分進んできたにもかかわらず、
相変わらずBRタグだけは改行する為に使われ続けているので、これもスタイルにしちゃおうという提案ですね。
最近はもうBRタグを記述する事は減りましたが、デザイン的にどうしてもpを使わず改行を入れたい場合にBRタグを使っているので、
どうせならそこもcssで解決できるようにはして欲しいですね。

vagrantでansible

vagrantイメージのプロビジョニングにansibleを使う方法をメモメモ。

  • playbook.ymlを作成する
---
- hosts: all
  tasks:
    - name: step1 (install docker)
      shell: curl -sSL https://get.docker.com/ | sudo sh

    - name: step2 (install libselinux-python)
      yum: name=libselinux-python state=present

    - name: step3 (disable selinux)
      selinux: policy=targeted state=permissive
      sudo: yes
  • Vagrantfile
    Vagrant.configure(2) do |config|
      ...
      config.vm.provision "ansible" do |ansible|
        ansible.playbook = "playbook.yml"
      end
    end
    

golangでツールを一つ作ろうと思ってるので、ついでにansibleにも勉強しようかなーと。
chefやpuppetよりもシンプルで取っつきやすいよね。

ninja frameworkとplayの比較

play2系を触ってみて1系から劣化したなーと思うところがninjaではどうなってるか見てみました。

環境毎の設定切り替え

play2系ではprefixによる設定の切り替えは廃止され、環境別の設定ファイルを用意する仕様になりました。
個人的には、小規模で使う分には1ファイルに全環境の設定を書いておきたいので、若干劣化したなぁ、という感覚でした。
ninjaはほぼほぼplay1系と同じ仕様で、起動時に渡す変数をprefixとして設定を切り替える形です。こちらの方が使いやすいかなー。

http://www.ninjaframework.org/documentation/configuration_and_modes.html

  • 起動時に ninja.mode を設定。
    mvn ninja:run -Dninja.mode=dev
    

  • application.conf

    database.name=database_production
    %dev.database.name=database_dev
    

自動実行ジョブ

play1系ではQuartzを使い、cronライクにシンプルに実装できましたが、
2系ではAkkaベースとなり設定の記述が複雑になってしまい、使いづらくなりました。
また、cronのように指定のタイミングで実行するのではなく、起動時から定期的に実行するだけの仕組みになりました。
ninjaではどうなったのか調べてみました。

http://www.ninjaframework.org/documentation/scheduler.html

  • Jobクラス
    @Singleton
    public class ScheduledAction {
        @Schedule(delay = 60, initialDelay = 5, timeUnit = TimeUnit.SECONDS)
        public void doStuffEach60Seconds() {
            // do stuff
        }
    }
    

  • Job登録

    public class Module extends AbstractModule {
        protected void configure() {
            bind(ScheduledAction.class);
        }
    }
    

んー、記述は簡単ですが、できることはplay2系と同じですね・・・
cronのような仕組みはあまり好まれないんですかね?

Session

http://www.ninjaframework.org/documentation/basic_concepts/sessions.html

playのSessionはJava ServletのHttpSessionとは全く異なる仕組みで実装されており、
サーバーには何も持たず、Cookieにすべてのコンテキストを保存します。
これはplayの思想であるshared nothingを実現するため、サーバー間でコンテキストを共有しないようにするためです。

ninjaもこの思想は引き継がれているようで、ninjaのSessionオブジェクトに値を設定すると、ブラウザのCookieに保存する仕様になっていました。
小規模ならLBでスティッキーにしてサーバーに全部保存したいんですが、やはりninjaでもサーバ側で保持したいコンテキスト情報は、Memcached等を併用する必要がありそうです。

Bootstrap4

alphaですが、Boostrap4が公開されていました。

http://v4-alpha.getbootstrap.com/

3系が長かったので、もうメジャーアップデートは無いのかなと安心していたらこれですよ。
ぱっと見はあまり3系から大きな変化はないようで、Blogの記載で気になったところは、

http://blog.getbootstrap.com/2015/08/19/bootstrap-4-alpha/

  • less から sass に移行
    lessもsassも使いこなせている訳ではありませんが、sassの方が優れているのでしょうか。
    Railsのフロントエンドで少しsassを使っている程度なので、そろそろ真面目に勉強してみようかな。

  • IE8のサポート終了
    以前から完全ではありませんでしたが、正式にIE8はサポートされなくなるようです。
    コンシューマサービスではあまり影響ありませんが、
    業務システムではIE8が現役のところも未だにあると思うので、これを機に情シスはWindows10を導入してIEからEdgeへ!(死にそう

Xamarin のライセンスが無償で取得できるかも

https://blog.xamarin.com/free-xamarin-subscriptions-for-windows-phone-developers/

8/17 以前にWindows Phone向けのアプリをリリースしたことがある開発者に対して、
Xamarin のライセンスを取得できるそうです。
Xamarin は.NETでiOSやAndroid向けモバイルアプリケーションを開発できるクロスプラットフォーム開発環境です。
ネイティブ実行できるバイナリを出力するそうで、高速に動作するのが売りだそうです。

ちなみにこのライセンスの取得は 8/31 までだそうです。
私も申請してみました。ライセンスが提供されたら何か作ってみよう。

マイクロフレームワークなしがし Spark編

マイクロフレームワークなにがしにて、ninja framework を触ってみましたが、
今度は Spark というフレームワークにトライしてみようと思います。

Webサイト

http://sparkjava.com/

セットアップ

https://sparktutorials.github.io/2015/04/02/setting-up-a-spark-project-with-maven.html

チュートリアルの通りにやると、POMを書いてmain関数にルーティング(+コントローラ)を記述するだけですね。
ninjaはplayライクなフレームワークでしたが、sparkはsinatraを模倣したフレームワークのようです。

import static spark.Spark.*;

public class Main {

	public static void main(String[] args) {
		get("/", (req, res) -> "hello world");
	}
}

main関数をjavaコマンドなどで通常のjavaアプリケーションとして実行します。
すると、Webサーバーが起動するので、ブラウザで http://localhost:4567 を開いて、hello worldが表示されればOK。

hello world

Viewのカスタマイズ

上記はレスポンスをそのまま返すだけなので、
今度はviewをテンプレート化します。

各種テンプレートエンジンの実装は、jarに分離されているので、下記を参考に、pomに依存関係を追加します。
http://sparkjava.com/documentation.html#views-templates

今回は、FreeMarkerを使った場合を試してみました。

  • Model
    public class Book {
    	private String name;
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    }
    

  • Controller

    public class Main {
    
    	public static void main(String[] args) {
    		Book book = new Book();
    		book.setName("日々創造");
    
    		get("/", (req, res) -> new ModelAndView(book, "book.ftl"), new FreeMarkerEngine());
    	}
    }
    

  • View (src/spark/template/freemarker/book.ftlに配置するのがポイント)

    book name: ${name}
    

  • 出力結果

    book name: 日々創造
    

テンプレートのディレクトリがデフォルトで spark/template/freemarker になっているので注意。
sinatraライクに書きたい方はsparkはオススメなのではないでしょうか。
個人的にはninjaの方が好みかも?

MySQL設定メモ2

MySQL設定メモ に続いて、今回はレプリケーションの設定項目について書きます。

log-bin

まず設定する項目であるバイナリログ有効化。
物理ディスクを分ける事ができる場合は、別のディスクに出力されるようパスを設定しておくのが良いです。

server_id

サーバーを区別するIDの設定。
これも最初に設定する項目ですね。
どのような値を設定するかいつも悩んでしまいます。
ロール毎に1000の位を連番で割り当てる等、構成管理のルールに合わせて決めましょう。

binlog_format

バイナリログのフォーマット設定。
デフォルトはMIXEDになっていますが、私はROWにします。
ROWの場合、バイナリログのサイズは増えますが、不整合が起きにくくなるのと、
更新された列のデータが完全な状態で残るので、何か問題が起きた際に、バイナリログを調査しやすくなる、という事があります。

expire_logs_days

自動削除する期限の設定(日数)。
大体7日〜14日を設定しています。
ディスクフルにならない程度に、少し長めにしておいた方が若干安心です。

slave_compressed_protocol

バイナリログの出力量が非常に多い場合、この設定を有効化すると、
master – slave間の通信が圧縮され、バイナリログ転送の高速化が期待できます。
master/slave両方で設定する必要があります。

slave_parallel_workers

slave側のバイナリログ適用を並列化する設定。
いわゆるSQLスレッドを複数に稼働させます。
一つ制限があり、1つのSQLスレッドは1つのDBしか処理できません。
DBが2つしか存在しないのに、slave_parallel_workers=4 と設定しても、2スレッドしか稼働しないということです。
この設定は一度導入したことがあるのですが、動作が不安定で定期的にInnoDBがクラッシュするようになったため、長期運用した経験はありません。

master_info_repository, relay_log_info_repository

master.infoやrelaylog.infoの管理をどこでするか、という設定。
master_info_repository=TABLE とすると、InnoDBで管理されるようになります。
ファイルベースでは無く、InnoDB化することで何がうれしいかというと、クラッシュセーフになるということ。
また副次的な作用として、master.infoの書き込みが高速化されます。
レプリケーションの遅延が気になる方は、一度変更してみても良いかもしれません。

このあたりでしょうか。後はshow slave statusを適宜監視するようにしておく等、
レプリケーションがクラッシュしたことを検知できるようにしておくことも必要ですね。

MySQL設定メモ

インストール後、いつも変更するMySQLの設定をメモ。
特にinnodb_file_per_tableと文字コード周りは運用後に変更しにくいので、最初に設定しておくこと!

参考

sql_mode

STRICT_TRANS_TABLESを追加して、
列制約に違反する形でデータを書き込むとエラーが発生するように指示します。
サイズオーバーだったり、Not Null列にNullを挿入しようとした場合にエラーハンドリングできるようになります。

innodb_file_per_table

InnoDBの実データが格納される.ibdファイルをテーブル毎に作成します。
これを設定しておかないと、ibdataXに全テーブルのデータが詰め込まれてしまいます。
テーブルを削除してもibdataXは縮小されることは無く、空き領域として再利用される事となります。
ディスクの空き容量が少なくなった場合に困るため、innodb_file_per_tableは必ず有効にしています。

innodb_buffer_pool_size

InnoDBの割り当てメモリ。基本的な設定ですね。
けちらずどかんと割り当てましょう。

innodb_log_file_size

REDOログのファイルサイズ。
InnoDBのクラッシュ時のリカバリにも使われます。
大きなトランザクションのパフォーマンスが向上するので、
バックアップのリストアにかかる時間も改善します。
場合によりけりですが、最初は128MB〜256MBに設定しています。
なお、この値を変更する際、MySQLの停止後、ib_logfileXを削除してからMySQLを起動する必要があります。

innodb_file_format

Barracudaにしておくことでメモリ効率が良くなる・・らしい。
5.6以降はデフォルトのmy.cnfに記述されているかも。
※5.6以降デフォルトかもというのは勘違いでした

character_set_client, character_set_connection, character_set_database

文字コードの設定。
ちょっと前まではutf8だったんですが、最近はサロゲートペアを含むutf8mb4にしておいた方が無難です。

collation_database, collation_connection, collation-server

照合順序の設定。
utf8mb4の場合は色々あるのですが、個人的にはutf8mb4_binに設定したい。
デフォルトはutf8mb4_general_ciになるのですが、こいつはアルファベットの大文字と小文字を区別しません。
たとえばユニーク制約を設定した際、”aaa”と”AAA”は同じ値となり、同時に挿入する事はできません。
また、”aaa”という値を検索した際、”AAA”が検索にヒットします。
便利ではあるのですが、ユーザIDの検索や、重複チェックの際に誤爆してしまうリスクが怖いので、経験上collateは完全一致になるようにしたいです。

slow_query_log, slow_query_log_file, long_query_time

スロークエリの設定。
long_query_timeは1ぐらいにしています。

max_connections

最大コネクション数。これも基本的な設定です。
コネクションあたりのメモリを計算して、
innodb_buffer_pool_sizeと足した値が物理メモリサイズを越えないよう気をつけつつ、適切な値にしておきましょう。

tmp_table_size, max_heap_table_size

一時テーブルのサイズとheapテーブルの最大サイズを指定します。
一時テーブルの場合は、この2つの設定両方の最小値を見るため、同じ値に設定しておきましょう。
物理メモリと相談ですが、なるべく大きい値にしたいところ。

細かいチューニングをしていくとまだ色々とあるのですが、
簡易的な初期設定はこんなところでしょうか。
また、レプリケーションの設定をする場合はさらに色々とチューニングが可能です。

マイクロフレームワークなにがし Ninja編

最近Play frameworkに影響されたフレームワークがいくつか出ているようで、
マイクロフレームワークと呼ばれているようです。

Ninja Framework

今日ははその一つである Ninja framework を見ていきたいと思います。
とりあえず公式サイトに沿ってチュートリアルを動かしてみます。

http://www.ninjaframework.org/documentation/getting_started/create_your_first_application.html

mvn archetype:generate -DarchetypeGroupId=org.ninjaframework -DarchetypeArtifactId=ninja-servlet-archetype-simple
cd ninja-servlet-archetype-simple
mvn clean install
mvn ninja:run

これでとりあえず開発サーバが起動します。
Playのようにバイナリパッケージを展開してコマンドにPATHを通したりといった作業が必要ないところはいいかも。
ちなみに開発サーバのポートを変えたい場合は下記の通り。

mvn ninja:run -Dninja.port=8081

ブラウザで localhost:8081 を開くと初期状態のHomeが表示されます。
最初からwebjarsのbootstrapが組み込んであって好印象。

DBアクセス

続いてDBアクセスを試します。
これもチュートリアルに書いてあるとおり。
http://www.ninjaframework.org/documentation/working_with_relational_dbs/jpa.html

テーブルの作成はpersistence.xmlに下記の設定を追加し、JPA(Hibernate)に任せるのが基本的には楽ですが、

<property name="hibernate.hbm2ddl.auto" value="update"/>

自前でマイグレーションSQLを用意してテーブルを作成したい場合は、
Flyway というライブラリに則ってやる事も可能なようです。

  • conf/application.confに追記
    ninja.migration.run=true
    

  • db/migration/V1__hogehoge.sql
    create table Hoge (
      id int(11) primary key,
      name varchar(255)
    );
    

自動的にV1__hogehoge.sqlがDBに適用されます。テーブル名がおかしい場合など、自動的にFlywayがバリデートしてくれるようです。
個人的には開発中はHibernateの自動スキーマ作成に頼り、運用中は検証済みのDDLファイルを慎重に適用したい派なので、Flywayを使うことは無いかもしれません。
(Flywayのバリデートで謎のエラーが出て地味にハマったので・・・)

ちょっと触った感想

  • Controller,ViewがPlay1系に近い感じで好印象
  • DB周りは素のJPAなので、取っつきやすい反面、PlayのModel程は使いやすくなさそう
  • バイトコードをいじらないようなので、若干安心

しばらく触ってみたいと思います。

Scalaを使ったプラガブルな実装

昔作ったScalaの言語構文とEvalの仕組みを利用した自作プラグインの作り方を紹介します。

Evalする部分については、こちらの記事を参考にさせて頂きました。
http://d.hatena.ne.jp/xuwei/20140607/1402128646

package parsers

import scala.reflect.runtime.currentMirror
import scala.tools.reflect.ToolBox
import java.io.File
import scala.io.Source

object Parser {
  def eval[T](code: String): T = {
    val toolbox = currentMirror.mkToolBox()
    val tree = toolbox.parse(code)
    toolbox.eval(tree).asInstanceOf[T]
  }

  def evalFile[T](file: File): T = {
    eval[T](Source.fromFile(file).getLines.mkString("\n"))
  }
} 

次に、Pluginの基底クラスを用意します。

package plugins

trait Plugin {
  def abstractMethod()
}

次は、Pluginの実装ファイル(PluginImpl.scala)を用意します。

new plugins.Plugin {  
  def abstractMethod() {
    println("hello")
  }
}

最後に、動的にファイルを実行してPluginをインスタンス化し、Plugin#abstractMethodを呼び出すメインとなるコードを実装します。

object Main {
  def main(args: Array[String]) {
    val pluginFile = new java.io.File("./PluginImpl.scala")
    val plugin = parsers.Parser.evalFile[plugins.Plugin](pluginFile)
    plugin.abstractMethod
  }
}

scalaファイルはコンパイルしてjarにし、PluginImpl.scala を同じ階層に配置して実行してみます。

$ java -jar Main.jar
hello

実際のシステムに実装する際には、特定のディレクトリ以下の.scalaファイルをすべて読んでインスタンス化したり、
一度読んだ後も、定期的にファイルのタイムスタンプをポーリングし、アプリケーションの再起動なしにプラグインをリロードできるようにしていました。
タイプセーフな設定ファイルなどもこの仕組みを使って実装し、システムを堅牢にするのに一役買っていました。