serverless + webpack + babel で AWS Lambda をナウく書く
イントロ
最近 AWS Lamdba を仕事で触っています。
serverless やら Apex なり色々あるわけですが、沢山ありすぎてよくわかりません。
今までは Apex
の手軽さに甘えていましたが、そろそろ serverless
が本気を出してきたという噂を聞き、serverless
を使い始めています。
どうせ serverless
を使うなら、もう全部使い倒してやろうということで、babel
も意識高く使っていきたいわけです。
この記事では serverless
+ babel
を使うところまでをまとめました。
環境
serverless@1.1.0
serverless-webpack@1.0.0-rc.2
webpack@1.13.3
serverless
まずは雛形作成
# template 指定は必須 # `sls` は `serverless` コマンドの alias $ sls create -t aws-nodejs
serverless.yml
というファイルが設定ファイル。
これを早速いじっていく。コメントや公式のドキュメントがわかりやすい。
# serverless.yml を編集していく $ emacs serverless.yml $ git diff serverless.yml provider: name: aws runtime: nodejs4.3 + region: ${env:AWS_REGION} functions: - hello: - handler: handler.hello + imageResizer: + handler: index.handle
# service の deploy $ sls deploy # AWS Lambda 関数の deploy $ sls deploy function -f imageResizer # AWS Lambda 関数の実行 $ sls invoke -f imageResizer # Log の tail $ sls logs -f imageResizer -t
まず最初に sls deploy
で Service の deploy を行う。
この Service というのは serverless
用語の一つで、AWS Lambda を実行するための AWS インフラ全体を指す名称。
この Service を管理するために serverless
は CloudFormation を暗黙的に使用している。
うっかり region 指定を忘れると、sls deploy
を実行した時、serverless デフォルトの region である us-east-1
に、 CloudFormation の Stack が出来上がってしまうので要注意。
region はコマンドラインの option で渡すか serverless.yml
の provider
で指定する。
serverless-webpack
serverless を使って deploy はできるようになった。後は書いたコードを babel を使っていく。
serverless-webpack
プラグインがあって、これを使えば OK。
elastic-coders/serverless-webpack: Serverless plugin to bundle your lambdas with Webpack
外部の npm パッケージを使う場合
serverless-webpack
を使用している場合、任意の package を handler の中で require しようとすると、 webpack コマンドで失敗してしまう。
$ git diff --- a/index.js +++ b/index.js @@ -1,5 +1,6 @@ 'use strict'; +import gm from 'gm'; # sls コマンドは serverless コマンドの alias $ sls webpack —out .webpack ... ERROR in ./~/thread-sleep/~/node-pre-gyp/package.json Module parse failed: /Users/argerich/dev/serverless-image-resizer/node_modules/thread-sleep/node_modules/node-pre-gyp/package.json Unexpected token (2:8) You may need an appropriate loader to handle this file type. SyntaxError: Unexpected token (2:8) at Parser.pp$4.raise (/Users/argerich/dev/serverless-image-resizer/node_modules/acorn/dist/acorn.js:2221:15) …
この場合、webpack-node-externals
を使って、設定ファイルを調整する必要がある。
具体的には以下のような修正をする。
# webpack.config.js +const nodeExternals = require('webpack-node-externals'); + module.exports = { entry: './index.js', target: 'node', @@ -5,5 +7,6 @@ module.exports = { libraryTarget: 'commonjs', path: '.webpack', filename: 'index.js' - } + }, + externals: [nodeExternals()] };
# serverless.yml custom: webpack: webpack.config.js + webpackIncludeModules: true
webpack
を通した deploy は serverless deploy function -f
では行われない。
serverless deploy
で行う。
$ sls deploy Serverless: Deprecation Notice: Starting with the next update, we will drop support for Lambda to implicitly create LogGroups. Please remove your log groups and set "provider.cfLogs: true", for CloudFormation to explicitly create them for you. Serverless: Bundling with Webpack... Time: 578ms Asset Size Chunks Chunk Names index.js 2.17 kB 0 [emitted] main Serverless: Packing external modules: babel-polyfill@^6.16.0, gm@^1.23.0 Serverless: Packaging service… Serverless: Uploading CloudFormation file to S3… Serverless: Uploading service .zip file to S3… Serverless: Updating Stack… Serverless: Checking Stack update progress… ..... Serverless: Stack update finished… Serverless: Removing old service versions… Service Information service: serverless-image-resizer stage: dev region: ap-northeast-1 api keys: None endpoints: None functions: serverless-image-resizer-dev-imageResizer: arn:aws:lambda:ap-northeast-1:xxxxxx:function:serverless-image-resizer-dev-imageResizer ✨ Done in 27.52s.
まとめ
region
のデフォルトはus-east-1
なので、指定を忘れないこと。serverless.yml
に region を書いておく(ドキュメントの隅っこ にサラッと書いてある)
serverless-webpack
で外部 package 使う場合は、webpack-node-externals
を使う- deploy は
serverless deploy function
ではなく、serverless deploy
を使う
という話でした。
Apex と Serverless 両方使ってみての感想
個人的には Apex
のほうが学習コスト少なくて、機能もシンプルなので好き。
Serverless
はもれなく CloudFormation が付いてきて、管理運用の面で色々思うところがある。AWS Lamda だけ触りたいんや! と思ってる人にとって、いきなり CloudFormation が出てくるとびっくりする。
けどその分 serverless
は設定ファイルを柔軟に書けるし、プラグインは充実している。Apex
で微妙だと思った環境変数周りを、うまくカバーしているところは好印象。
一方で Apex
でしか出来ないことは Terraform
との連携だけ。この機能にどれだけ期待するかが、一つの採用基準でもあると思う。
しかし、ただ単に AWS Lambda を使いたい、というだけであれば Apex
で十分だし、落とし穴は少ない。
Apex
で不満に思うことが増えてきたら serverless
を検討する、で良いのかな。
と、当たり前の結論に至りました。
参考になる
- pierresaux/serverless-boilerplate: Serverless boilerplate with webpack
- serverless-webpack/examples at master · elastic-coders/serverless-webpack
おまけ
$ sls webpack —out .
とやると、現在のディレクトリが全て消されて途方にくれるので、 良い子のみんなは絶対に真似をしないでください
ファイル名で使えない文字
イントロ
web アプリケーションで、ユーザーにファイルをダウンロードさせる機能を追加したいとする。
例えばダウンロードさせるファイルの名前をアプリ側で自動決定する場合、その名前にはどのような制限があるのだろうか。
何回か調べてる気がするので、まとめてみる。
前提
そもそも、ファイル名の制限は、OS ではなく、基本的にはファイルシステムで決まる。
ファイルシステム上の限界
ファイルシステムの限界はどこまでなのかというと Comparison of file systems - Wikipedia, the free encyclopedia にまとめられている。
古いファイルシステムでは、ファイル名は 8 文字、拡張子が 3 文字、ドットも含めて合計 12 文字までしかダメ、という時代もあったらしい。8.3形式
と呼ばれているのがそれだ。
有名どころのファイルシステム(NTFS
, FAT系
, ext4
, xfs
)では
という仕様が多いようだ。
Windows で禁止されている予約語
ただし Windows は例外がある。
ファイルシステムだけでなく、OS レベルで予約されている文字があり、これらはファイル名として使えない。
Naming Files, Paths, and Namespaces (Windows) によると、以下の文字が予約されている。
< (less than) > (greater than) : (colon) " (double quote) / (forward slash) \ (backslash) | (vertical bar or pipe) ? (question mark) * (asterisk)
手元に win 機が無かったので、残念ながら検証はしていない。
本当にダメなのか試してみたい。
結論
対応するファイルシステムのカバー範囲により、ファイル名に使える文字は異なる。
だが、現実的な落とし所として
- windows を視野にいれるのであれば、windows で禁止されている予約語は使わないほうが良いと思う。
- 予約語 is
< > : " / \ | ? *
- 予約語 is
- NULL文字も使えないファイルシステムが多いため、止めたほうが無難。
- 長過ぎるファイル名は NG なので、そのあたりも調整する。
- マルチバイト文字のときが面倒くさいが、より小さい方に合わせ
255 byte まで
のほうががいいのかな。
- マルチバイト文字のときが面倒くさいが、より小さい方に合わせ
ぐらいを考えておけば良さそうだろうか。
おまけ
https://en.wikipedia.org/wiki/Comparison_of_file_systems によると、制限は以下の通り
File system | Maximum filename length | Allowable characters in directory entries | Maximum pathname length | Maximum file size | Maximum volume size |
---|---|---|---|---|---|
HFS Plus | 255 UTF-16 characters | Any valid Unicode | Unlimited | slightly less than 8 EiB | slightly less than 8 EiB |
# 制御文字のファイル名は作れる `touch "\a"` => "" # null 文字はダメだった `touch "\x0"` # ArgumentError: string contains null byte # from (irb):1:in ``' # from (irb):1 # from /Users/argerich/.rbenv/versions/2.3.0/bin/irb:11:in `<main>' # 256 byte は長すぎる `touch #{"a" * 256}` touch: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: File name too long # 255 byte なら OK `touch #{"a" * 255}` => "" # 日本語で 255 文字はアウト `touch #{"あ" * 255}` touch: あああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああ: File name too long >> "あ".bytesize => 3 # 3 * 85 = 255 なので、85 文字まで OK >> `touch #{"あ" * 85}` => "" # 86 文字目からアウト >> `touch #{"あ" * 85 + "a"}` touch: あああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああa: File name too long # UTF-16 が OK ならば、絵文字でもいけるはず。 `touch #{"\u{26C4}" * 85}` => ""
絵文字ファイル名で作れているっぽい。ls
すると ?
になるけど。
それにしてもWikipedia 先生。ファイル名の長さ、255 byte までなのでは?
Any valid Unicode
の中に null 文字は入ってないのかな?
一部の文字は互換性維持のため、OS の API で制御しているとの噂もあるけど… うーむ。
情報が少なすぎて、これ以上調べるのは難しそうだった。一次情報どこにあるの。
試してみたものの、Wikipedia を引用してまとめたので、すごい微妙になってきた…
この記事は用法用量を守って、正しくお使いください。
参考
AppStore でアプリのアップデートができなくなった件
イントロ
「この製品のディストリビューションファイルを検証できませんでした。
破損しているか、署名されていない可能性があります」
と出て、update できない。
状況
- 上記のようなメッセージが出て、更新通知があるアプリを更新できない
- 何故か更新できるアプリもある
- キャッシュを消しても出る
- 試したのは
% sudo rm -rf ~/Library/Caches/* /Library/Caches/*
- 乱暴なので、良い子は真似しないように。
- 試したのは
/var/log/system.log
に以下のようなメッセージが出力される-
Assertion failure in -[CheckPreflightOperation verifyDistributionAtURL:allowsDevSign:allowsUnsigned:osVersionToBeInstalled:error:distributionController
-
# /var/log/system.log Sep 2 11:54:11 --- last message repeated 1 time --- Sep 2 11:54:11 argerich-no-Mac-mini iTerm2[348]: Time to encode state for window <PseudoTerminal: 0x7f8544b54630 tabs=1 window=<PTYWindow: 0x7f8542d2b920 frame=NSRect: {{0, 74}, {1918, 972}} title=1. Horowitz (tmux) alpha=1.000000 isMain=0 isKey=0 isVisible=1 delegate=0x7f8544b54630>>: 0.003149032592773438 Sep 2 11:54:15 argerich-no-Mac-mini storedownloadd[583]: *** Assertion failure in -[CheckPreflightOperation verifyDistributionAtURL:allowsDevSign:allowsUnsigned:osVersionToBeInstalled:error:distributionController:], /Library/Caches/com.apple.xbs/Sources/Commerce/Commerce-463.9/CommerceKit/CheckPreflightOperation.m:291 Sep 2 11:54:23 argerich-no-Mac-mini iTerm2[348]: Time to encode state for window <PseudoTerminal: 0x7f8544b54630 tabs=1 window=<PTYWindow: 0x7f8542d2b920 frame=NSRect: {{0, 74}, {1918, 972}} title=1. Horowitz (tmux) alpha=1.000000 isMain=0 isKey=0 isVisible=1 delegate=0x7f8544b54630>>: 0.004208028316497803 Sep 2 11:54:27 argerich-no-Mac-mini iTerm2[348]: Time to encode state for window <PseudoTerminal: 0x7f8544b54630 tabs=1 window=<PTYWindow: 0x7f8542d2b920 frame=NSRect: {{0, 74}, {1918, 972}} title=1. Horowitz (tmux) alpha=1.000000 isMain=0 isKey=0 isVisible=1 delegate=0x7f8544b54630>>: 0.004567980766296387
解消法
ゲストユーザーでログインし、アップデートしたら成功。
恒久対応ではない気がする。
Java 歴 23 分の Ruby エンジニアが Effective Java を読んで感動した話
イントロ
例外処理を書くことはよくやっているのだけれど、その時の主軸となる考え方について、今までなんとなくで行っていた部分が多かった。
毎回考えるポイントは例えば以下のような疑問。
- どこのレイヤーで、どこまで例外処理を行えばよいのだろうか?
- どの例外をキャッチし、どの例外を伝搬させればよいだろうか?
- 前提条件をチェックし、失敗した場合、例外を出したほうがよいか、
nil
,false
を返すほうがよいか? - 例外をどういう単位でラップさせるのが良いだろうか?
- 例外をチェインし過ぎると却って煩雑になる気がする。どうすれば良いのだろうか。
しかし、この辺りの話って、API の設計だったり、仕様の影響もあるので、都度対応が異なってしまうもの。
したがって抽象化して理解することが難しく感じた。
とてもよく使ってるし、とても大事な事なことなのに。
そんな今更な事で悩んでいた時に、Effective Java
という良い本を紹介してもらったので、例外処理の章を読んでまとめてみました。
(5 章まで読んで力尽きていたが、勇気を振り絞り、また読み進めてみた)
EFFECTIVE JAVA 第2版 (The Java Series)
- 作者: Joshua Bloch,柴田芳樹
- 出版社/メーカー: 丸善出版
- 発売日: 2014/03/11
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (10件) を見る
- イントロ
- 読書メモ
- 感想
- 2017/11/22 追記
読書メモ
項目.57 例外状態の時だけ例外にする
// 行ってはならない try { int i = 0; while(true) range[i++].climb(); } catch(ArrayIndexOutOfBoundsException e) { }
- 例外に基づくイディオムはパフォーマンスが悪い
- そのため、例外の目的がわからない場合は使ってはいけない
- 例外は例外的条件の時のみに使用する。通常の制御フローに対しては使ってはいけない
- コードの保守性を落とすだけでなく、パフォーマンスも悪くなるので
- 通常の制御に例外を使用することをクライアントに強制してはならない
- 例えば、予測不能な状態でのみ呼び出されるメソッドは「状態依存 」である
- e.g)
Iterator#next()
- e.g)
- 一般には状態を判別する状態検査メソッドを持つべき
- e.g)
Itereator#hasNext()
- e.g)
- 状態検査メソッドが呼ばれること無く、状態依存のメソッドが呼ばれた場合は、そうとわかるような特別な値を返す
- 例えば、予測不能な状態でのみ呼び出されるメソッドは「状態依存 」である
状態検査メソッドを使うか、区別できる戻り値を使うか
区別できる戻り値を使う場合
以下の条件を満たすとき。
- 並行してアクセスされる場合
- 外部要因で状態遷移する場合
状態検査メソッドと、その変更メソッドを呼び出す間に、状態が変更になる場合があるから。
状態検査メソッドを使う場合
上記以外のとき。
- 若干読みやすい
- 状態検査メソッドを呼び出すことを忘れると、例外が投げられるため、バグに気づきやすい。
から。
項目.58 回復可能な状態にはチェックされる例外を、プログラミングエラーには実行時例外を使用する
チェックされる例外(checked exception)
- 回復可能な状態であるときに発生する例外
- 回復に役立つ情報を提供するメソッドを持つと良い
実行時例外(runtime exception)
- 回復可能でない状態である場合に発生する例外 = チェックされない例外
- 実行を続けても役にたたない、むしろ害になるような場合に発生する例外
RuntimeException
をサブクラス化する
- 「回復可能かそうでないか」を判別できない場合も「実行時例外」として扱うべき
エラー(error)
- 基本的には使わない
- API のユーザーの混乱を招くだけだから
- 得られるものは殆ど無いから
項目.59 チェックされる例外を不必要に使用するのを避ける
チェックされる例外は、API の使用者に例外処理を強制させ、信頼性を上げる
しかし、チェックされる例外を過剰に増やすと逆に API を使いにくくする。 API を使う側は、以下の2つのどれかを強いられるため、多少の負荷がかかるから。
- 少なくとも1つ以上の catch が必要
- 例外を外側に伝搬させる
チェックされる例外を使う場合
この2つの条件をみたす場合に、上記の負荷が正当化される。(ただし CloneNotSupportedException
は例外)
それ以外の場合はチェックされない例外のほうが適切。
チェックされる例外を、チェックされない例外に変更する方法
上記で述べたように、チェックされる例外を使用し過ぎると、負荷が高くなる。 その方法が「例外を投げるメソッドを分割して、状態検査メソッドと、それ以外の処理に分割する」というもの
ただし、以下の場合は NG。
- 外部同期なしに平行してアクセスされる場合
- 外部要因により、状態遷移する場合
actionPermitted
メソッドが action メソッドの処理を行う必要がある場合- (パフォーマンス上の関係で、この分割を行う必要がないので不要となる)
// チェックされる例外を使用する場合の呼び出し try { obj.action(args); } catch(TheCheckedException e) { // 例外処理 }
// 状態検査メソッドとチェックされない例外を使用する場合の呼び出し if (obj.actionPermitted(args)) { obj.action(args); } else { // 例外処理 }
項目.60 標準例外を使用する
既存の例外を再利用する
- プログラマが熟知している確立された慣例と一致するため、使用が容易になるから
- 見慣れない例外でごちゃごちゃしないので、API を使用するプログラムが読みやすい
- 例外クラスが少ないことは、クラスのロードに費やされる時間が少ないことを意味する
よくある具体例
IllegalArgumentException
- 不適切な引数を渡した時に発生する例外
IllegalStateException
- レシーバーのオブジェクトが不正な状態ならば発生する例外
NullPointerException
- null が禁止されているパラメータに対して、null を渡した場合など
IndexOutOfBoundsException
- index を表すパラメータで、範囲外の値を呼び出した場合など
ConcurrentModificationException
- 並行して変更されようとしている
UnsupportedOperationException
- 行おうとした操作をオブジェクトがサポートしていない場合
また、エラーに関連する情報を付与したい場合は、自由に例外をサブクラス化すること。 再利用する時の例外をどう選択するか、は必ずしも厳密でない場合がある
項目.61 抽象概念に適した例外をスローする
例外翻訳とは
「上位レイヤは下位レベルの例外をキャッチし、上位レベルの抽象概念の観点から説明可能な例外をスローする」こと。例えば以下の様な例を指す。
// イディオム try { } catch (LowerLevelException e) { throw new HighLevelException(...) }
// AbstractSequentialList からの一例 public E get(int index) { ListIterator<E> i = listIterator(index); try { return i.next(); } catch(NoSuchElementException e) { throw new IndexOutOfBoundsException("Index: " + index); } }
上位レベルの例外から、下位レベルの問題をデバッグするためには、例外連鎖を用いる
- 上位レベルから下位レベルの例外を取り出すためのアクセサを用いる
- 具体的には、スーパークラスの連鎖可能なコンストラクタに引き渡す
- 殆どの標準例外は連鎖可能なコンストラクタを持っている
try { // Do something } catch (LowerLevelException cause) { throw new HighLevelException(cause); } class HighLevelException extends Exception { HighLevelException(Throwable cause) { super(cause); } }
例外翻訳は何も考えないで例外を伝搬させるよりは優れてるが、乱用すべきではない
- 可能であれば、下位レベルのメソッドを呼び出す前に、それが成功することを保証する
- (状態検査メソッドのこと?)
- 引数を引き渡す前に、正当性を検査する
- 不可能であれば、上位レイヤに黙って処理させる
- 下位レベルの問題から、上位レベルのメソッド呼び出し元を隔離する事が次善策
- 呼び出し元を隔離出来ない場合は、例外連鎖を使う
項目.62 各メソッドがスローする全ての例外を文章化する
例外がスローされる条件を Javadoc の @throw
タグで正確に文章化する
チェックされない例外についても、注意深く文章化するほうが懸命
- ただし、強制はしない
- 書くことで、メソッドが首尾よく実行されるための事前条件を記述できる
- これは必ずしも達成可能であるとは限らない
-
throw
タグを使わない- チェックされない例外と、チェックされる例外を視覚的に区別するため
項目.63 詳細メッセージにエラー記録情報を含める
例外の toString
メソッドが例外の文字列表現である
- 文字列表現 = クラス名 + 詳細メッセージ
- エラーの原因を表す文字列で、できるだけ多くの情報をかえす事が重要
例外の原因となった全てのパラメータとフィールドの値を含んでいるべき
- 例)
IndexOutOfBoundsException
は下限範囲、上限範囲、範囲内の収まらなかった実際の index を返す。これは診断にとても役立つ情報
例外の文字列表現と、エンドユーザーに対してわかりやすいメッセージを混同すべきではない
- プログラマにとっては、エラーを解析する情報の内容のほうがはるかに重要
- 以下の様にコンストラクタを作成することを推奨
- プログラマがエラーを記録することが容易になるし、逆に記録しないことが困難になるから
- 高品質な文字列表現を生成するコードを一箇所にまとめる事ができるから
- アクセサを提供することで、エラーからの回復に役立てることができるかもしれないから
/* IndexOutOfBoundsException を生成する @params lowerBound 最も小さな正当なインデックス値 @params upperBound 最も大きな正当なインデックス値に 1 を足した値 @params index 実際のインデックス値 */ public IndexOutOfBoundsException(int lowerBound, int upperBound, int index) { super("Lower bound: " + lowerbound + ", Upper bound: " + upperBound + ", Index: " + index); this.lowerbound = lowerBound; this.upperBound = upperBound; this.index = index; }
項目. 64 エラーアトミック性に努める
エラーアトミックとは
- 「失敗したメソッド呼び出しは、オブジェクトをそのメソッド呼び出しの前の状態にしておく」という状態
- なるべくエラーアトミックに保つことを意識する
エラーアトミックを保つための方法
- 不変オブジェクトを設計する
- 変更できないので、エラーが出ても同じ状態であるから
- パラメータの正当性を検査する
- オブジェクトの変更を行う前に例外をスローすることができるから
- 失敗するかもしれない部分を、オブジェクトを変更する部分よりも前に行う
- 操作の途中で発生する例外を捉えて、状態を戻す「回復コード」を書く
- 一般的ではない
- 主に永続的なデータ構造に対して使用される
ただし、エラーアトミック性は必ずしも達成できるとは限らない。例えば複数スレッドが同期なしに、同一オブジェクトを同時に変更する場合など。
メソッドがエラーをスローする場合は、一般的には回復不可能であり、エラーアトミック性を保持しなくてよい
- たとえ回復可能でも、必ずしも望ましいとは限らない
- 例外は回復可能である場合がある。対比に注意
- メソッドの仕様の一部である例外は、エラーアトミック性を保持するべき
// 最初のサイズ検査が無くても例外を投げる // しかし、それだと size フィールドを不正号な状態にしてしまい // オブジェクトに対するその後の呼び出しを失敗させてしまう public Object pop() { if (size == 0) throw new EmptyStackException(); Object result = elements[—size]; elements[size] = null; // 廃れた参照を取り除く return result; }
項目.65 例外を無視しない
例外を無視してはいけない理由
- 例外の目的が達成されないから
- 例外の目的とは、例外的状態を処理させることを強制する、こと
- 火災報知機を無視して、警報を切ってしまうのと同じ
- 無視する場合はコメントに含んでいるべき
- エラーをも無視してしまうから
- 原因とは何も関係のないところでエラーになる可能性がある
- 例外は、外に伝搬させるだけでも有益な情報を残してくれる
// ダメ、ぜったい try { } catch (SomeException e) { }
感想
普段は ruby を書いているが、早速活かせそうな話ばかりだったので、試してみたい。
例外処理を書く時の指針が揃っていたし、その理由も納得できるものだった。特に「チェックされる例外」と「チェックされない例外」という考え方は自分が特に迷っていた部分だったので、参考になった。 例外連鎖を使うときにも指針ができた。
Java は型あるので、擬似コードが理解し易くていいですね。
こういうプログラミング全般?の話というか、プログラミングテクニックというか、そういう本って他にもあるのかな。
基礎力が無いのでもっと読んだほうが良い気がする。Effective Java
も更に読み込んでいきたい。
2017/11/22 追記
かなりスペースを取ってしまってますが、冒頭に目次を追加しました。
忙しい人でも目次だけ読んで、気になったところだけ読めるようにする意図を込めてます。
rails 5 を今更触ってみた話
イントロ
rails5 の主要機能は色々と知られている通りだけど、業務に投入するとなると、やっぱり互換性だったり、細かいコードの違いが気になるもの。
今回 authlogic を使ったログイン機能を雑に作ったので、その限られた狭い範囲であるものの、ハマったところや違いをまとめてみた。
なんで authlogic ?
- 昔業務で使ってたから。そしてまた使うかもしれない。
- なお
devise
は初心者の頃使って見事に爆死し、それ以降使ってない。
- なお
- そこそこ古く、歴史ある gem
rails5
でも使えるかどうか確かめたかった- binarylogic/authlogic_example は 7 年前の化石となっている。
- シンプルな機能だけを提供してくれている
- だから好き。
- (ただし、中身はかなり癖のある実装)
- 昔のおさらい。復習を兼ねて。
環境
rails (5.0.0.rc2)
authlogic (3.4.6)
rspec-core (3.1.7)
気づいたこと
authlogic
は rails5 対応中
結論から言うと、今は使えなかった。
しかし対応 PR や issue も立っているので、しばらく傍観モード。
全くメンテナンスされていないわけではなさそうなので、少し安心した。
- Rails 5 callback by jealt · Pull Request #488 · binarylogic/authlogic
- Fix deprecation warning: prepend_before_filter in Rails 5 by bparanj · Pull Request #491 · binarylogic/authlogic
- Impossible to authenticate using Rails 5 (beta 3) and Authlogic 3.46 · Issue #487 · binarylogic/authlogic
サンプルを作成する時には、vendor/bundle
以下に install されている authlogic を直接修正して、無理やり動かすことになってしまった。
トップページが….
初めて rails s
して localhost:3000
にアクセスするとこんな感じ。かっこいい。
ログを見ると以下のようになっている。
Started GET "/" for 127.0.0.1 at 2016-06-25 22:55:12 +0900 ActiveRecord::SchemaMigration Load (0.6ms) SELECT "schema_migrations".* FROM "schema_migrations" Processing by Rails::WelcomeController#index as HTML Parameters: {"internal"=>true} Rendering vendor/bundle/gems/railties-5.0.0.rc2/lib/rails/templates/rails/welcome/index.html.erb Rendered vendor/bundle/gems/railties-5.0.0.rc2/lib/rails/templates/rails/welcome/index.html.erb (4.5ms) Completed 200 OK in 24ms (Views: 11.3ms | ActiveRecord: 0.0ms)
Rails::WelcomeController#index
というのが呼ばれている。
書き換えたいときは今までどおり、root
を設定すればいいっぽい。
controller のテストが rails-controller-testing
に切り出されている
assigns
が使えなくて、scaffold
で作ったテストが NoMethodError
で落ちる。
assigns
を使いたければ rails/rails-controller-testing を各自で install して使う仕組みになったようだ。(対応したのはもっと昔なのだろうけど、知らなかった)
rspec
は minitest
とは違って、全部まるごと入ってるのが嬉しいから、個人的にはちょっと残念。今後の方針がどうなるかは知らないけど、テストのために色々な gem を探したり install するのは大変だし、面倒だと思う。その面倒さが無いのが一番の利点だと思ってたので。*1
prepend_before_filter
が deprecated
authlogic
の内部で書かれている。
なので bundler
で環境を読み込むたび出てくるので鬱陶しい。
$ rails c DEPRECATION WARNING: prepend_before_filter is deprecated and will be removed in Rails 5.1. Use prepend_before_action instead. (called from require at /Users/argerich/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/bundler-1.11.2/lib/bundler/runtime.rb:77) Loading development environment (Rails 5.0.0.rc2) >>
メッセージにも書いてあるとおり、prepend_before_action
を使えば警告を解消できそう。
use_transactional_fixtures
が deprecated
rspec-rails
の use_transactional_fixtures
が deprecated になっている模様。
代わりに use_transactional_tests=
を使えとあるけど、rspec-3.1.7
では対応されておらず、NoMethodError
で弾き返される。
$ rspec … DEPRECATION WARNING: use_transactional_fixtures= is deprecated and will be removed from Rails 5.1 (use use_transactional_tests= instead) (called from <top (required)> at /Users/argerich/dev/authlogic-rails5-example/spec/controllers/top_controller_spec.rb:3) DEPRECATION WARNING: use_transactional_fixtures= is deprecated and will be removed from Rails 5.1 (use use_transactional_tests= instead) (called from <top (required)> at /Users/argerich/dev/authlogic-rails5-example/spec/controllers/user_sessions_controller_spec.rb:3) DEPRECATION WARNING: use_transactional_fixtures= is deprecated and will be removed from Rails 5.1 (use use_transactional_tests= instead) (called from <top (required)> at /Users/argerich/dev/authlogic-rails5-example/spec/controllers/users_controller_spec.rb:21) DEPRECATION WARNING: use_transactional_fixtures= is deprecated and will be removed from Rails 5.1 (use use_transactional_tests= instead) (called from <top (required)> at /Users/argerich/dev/authlogic-rails5-example/spec/models/user_spec.rb:3) DEPRECATION WARNING: use_transactional_fixtures= is deprecated and will be removed from Rails 5.1 (use use_transactional_tests= instead) (called from <top (required)> at /Users/argerich/dev/authlogic-rails5-example/spec/requests/users_spec.rb:3) …
Deprecation warning: use_transactional_fixtures= is deprecated · Issue #1549 · rspec/rspec-rails を見ると、master branch では対応しているっぽい。
ActionController::TestCase
get url, parameter, session
でお馴染みの、リクエストを送るメソッドの引数が、HTTP method だけになる模様。
get :show, params: { id: 1 }, session: { user_id: 1 } process :update, method: :post, params: { id: 1 } (called from block (3 levels) in <top (required)> at /Users/argerich/dev/authlogic-rails5-example/spec/controllers/users_controller_spec.rb:57) DEPRECATION WARNING: ActionController::TestCase HTTP request methods will accept only keyword arguments in future Rails versions.
具体的には、以下の様な修正を行えばおk。
引数に名前がついて、わかりやすくなった。地味に嬉しい。
しかし、これは多分運用しているテストを直さないといけなくなるのかなー。
--- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -60,7 +60,7 @@ RSpec.describe UsersController, :type => :controller do describe "GET new" do it "assigns a new user as @user" do - get :new, {}, valid_session + get :new, params: {}, session: valid_session expect(assigns(:user)).to be_a_new(User) end end
ログが綺麗になってる
前はもっと asset 周りのログが沢山流れていたが、今は出ない。
すっきり。
Started GET "/" for 127.0.0.1 at 2016-06-26 00:09:06 +0900 Processing by TopController#index as HTML Rendering top/index.html.erb within layouts/application Rendered top/index.html.erb within layouts/application (11.4ms) Completed 200 OK in 40ms (Views: 34.7ms | ActiveRecord: 3.1ms) Started GET "/login" for 127.0.0.1 at 2016-06-26 00:09:12 +0900 Processing by UserSessionsController#new as HTML Rendering user_sessions/new.html.erb within layouts/application Rendered user_sessions/new.html.erb within layouts/application (3.9ms) Completed 200 OK in 66ms (Views: 64.3ms | ActiveRecord: 0.0ms)
last_comment
が deprecated
Rake.application.last_comment
が deprecated らしい。
rspec-core
の 3.1.7
では、ここ に Rake.application.last_comment
が使われていて、警告が出る。
% rake DEPRECATION WARNING: prepend_before_filter is deprecated and will be removed in Rails 5.1. Use prepend_before_action instead. (called from require at /Users/argerich/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/bundler-1.11.2/lib/bundler/runtime.rb:77) [DEPRECATION] `last_comment` is deprecated. Please use `last_description` instead. [DEPRECATION] `last_comment` is deprecated. Please use `last_description` instead. [DEPRECATION] `last_comment` is deprecated. Please use `last_description` instead. [DEPRECATION] `last_comment` is deprecated. Please use `last_description` instead.
last_description
に書き換えると警告が止まる。
確認はしてないが、master なら治ってそう。
まとめ
休日の空いてる時間で、雑に作ったものですが、できあがったものはこちらです。
mgi166/authlogic-rails5-example: authlogic meets rails 5
*1:もっとも、最近では controller のテストではなく request のテストを書く事が多いだろうと思われるが
webpack-dev-server を使う
イントロ
見ればだいたい書いてある。
webpack
は少し触らないと忘れてしまうので、メモしておく。
それと何故か webpack の公式 Document は読みづらい(私だけ?)というのも理由の一つ。
webpack-dev-server って?
開発用の web サーバー。Express
で作られてる。
おおまかに2つのことができる
Hot Module Replacement
- module を変更したら変更を検知して読み込み直す
Automatic Refresh
- react とかで、component を変更したら、自動で reload する
これだけできれば、わざわざ変更のたびにサーバーを再起動しなおさなくて済むので、とりあえずの開発には困らなくなる。
導入
まずは npm install
$ npm i --save-dev webpack-dev-server
webpack.config.js を編集。
module.exports = { context: path.join(process.env.PWD, 'frontend'), - entry: "./index.js", + entry: [ + "webpack-dev-server/client?http://localhost:8080", + "webpack/hot/dev-server", + "./index.js" + ], output: { path: path.join(__dirname, 'dist'), - filename: 'webpack.bundle.js' + filename: 'webpack.bundle.js', + publicPath: "/assets/" }, @@ -14,7 +18,8 @@ module.exports = { plugins: [ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify(process.env.NODE_ENV) } - }) + }),[f:id:mgi:20160416232151g:plain] + new webpack.HotModuleReplacementPlugin() ],
やってることは 3 つ
- entry を増やす
webpack-dev-server/client?http://localhost:8080
,webpack/hot/dev-server
の2つ
- plugins に
webpack.HotModuleReplacementPlugin
を足す - output.publicPath: を設定
publicPath
の説明はこちら
後は option つけてコマンドラインで起動すれば良い
$ webpack-dev-server —hot —inline
まとめ
簡単に導入できて、凝ったことしない限りは十分なので非常に助かる。
magit と elscreen を使いやすく
イントロ
magit
と elscreen
は結構相性悪いと感じることが多く、今まで以下の様な点で困っていた。
- magit-mode を終了しても magit 用の buffer が消えない
- なんとなく気持ち悪い
- 1 つならまだしも、2 ~ 3個残る。
- elscreen 上で magit buffer を閉じた時、どの buffer が開かれるか、学習できなかった
- 本当は最後に作業していた buffer を開きたい。
- 条件によっては、何故か magit 用 buffer がスクリーンに残ったり 、わけがわからない
- 複数の elscreen 上で magit 動かすと、最後の buffer を全く覚えておらず、不思議な挙動をしているように感じてしまう。
- 本当は最後に作業していた buffer を開きたい。
何言っているかわからないと思うが、俺も何が起こってるかわからなかった。
magit
+ elscreen
で運用している人が少ないのか、あまりインターネッツに情報がない。
これはなんとなく magit 使いづらいと感じていた部分を少しだけ直した話になります。
やったこと
以下のような関数作って、フックに追加する。
これで二週間くらい運用して見た限りでは、だいぶストレスがなくなりました。
しかし、magit-status
毎に buffer を新しく生成しているので、PC リソース(というかメモリ)を上手に使えていないはず。
(defun elscreen-kill-all-scratch-screen () "Delete all scratch screen" (interactive) (dolist (screen-and-buffer (elscreen-get-screen-to-name-alist)) (when (and (string-match "*scratch*" (cdr screen-and-buffer)) (> (length (elscreen-get-screen-list)) 1)) (elscreen-kill (car screen-and-buffer))))) (defun delete-all-magit-buffers () "Delete all *magit-xxx* buffer" (interactive) (dolist (buffer (buffer-list)) (when (string-match "*magit" (buffer-name buffer)) (kill-buffer buffer)))) (defun magit-mode-quit-window () "Restores the previous window configuration and kills the magit buffer" (interactive) (delete-all-magit-buffers) (elscreen-kill-all-scratch-screen) (jump-to-register :magit-fullscreen)) (define-key magit-status-mode-map (kbd "q") 'magit-mode-quit-window) (defun with-editor-post-finish-hook-1 () (delete-all-magit-buffers) (elscreen-kill-all-scratch-screen)) (defun with-editor-post-cancel-hook-1 () (delete-all-magit-buffers) (elscreen-kill-all-scratch-screen))
VPC についてまとめ
イントロ
VPC 周りの知識が曖昧なままここまで来てしまったので、整理する。
なんとなく知っていた用語や単語について、一般的な概要、及び AWS ではどういう特徴をもっているか、を大雑把にまとめたもの。
VPC
概要
Virtual Private Cloud の略。Vrtial Private Cloud とは、クラウド環境に構築された仮想的なプライベートネットワークのこと。
VPC 自体が 1 つの IP アドレスを持っていて、VPC は沢山の private ip を持っている。
そんなインターネット上のでっかい領域を指す。
AWSでは
- VPC は CIDR =
x.x.x.x/16
~x.x.x.x/28
の間で作成可能 - デフォルトの VPC というものが存在する
- CIDR は一度作成したら変更不可
- 後からレンジを変えられないので注意
- VPC 削除のタイミングで、関連のAWS リソースは削除されてしまう
- subnet とか Internet Gateway とか色々。
- 削除して作りなおすと、全て作り直しになってしまうので、CIDR は余裕を持たせるのが基本
VPC の作成方法
VPC とサブネット - Amazon Virtual Private Cloud
インターネットゲートウェイ
インターネットゲートウェイ - Amazon Virtual Private Cloud
- VPC のルーティングを各サブネットのルーティングテーブルに追加できる
- NAT 変換を行い、public IP を持つ instance がインターネットに接続する
という機能を持つ。
AWS では
- デフォルトの VPC というものが存在する。
- インターネットゲートウェイがデフォルトの VPC にアタッチされている
- デフォルトのサブネットの中で起動したインスタンスは、public IP が付与される
- public の IP が付与されると、インターネットゲートウェイが NAT 変換を行える。
- つまりインターネットに接続できる
というわけで、何も考えずに EC2 インスタンスをポチると、外部と通信することができるようになるのは、AWS の素晴らしい挙動によるもの。
インターネットゲートウェイの作成
インターネットゲートウェイ - Amazon Virtual Private Cloud
ルートテーブル
ルートテーブル - Amazon Virtual Private Cloud
インターネットトラフィックがどこからどう流れていくか、を記した経路のこと。
どこからどこにトラフィックを流す、という対応表で表現される。
AWS では
ルートテーブル - Amazon Virtual Private Cloud
にまとめられてる。全部重要だけど最低限の機能としては次の通り。
- VPC を作成すると、ルートテーブルが自動で割り振られて、インターネットゲートウェイへのルートが追加されている。これを メインルートテーブル と呼ぶ
- サブネットを特定のルートテーブルに紐付けないと、メインルートテーブルに紐付けられる。
- つまり作成したサブネットはデフォルトでインターネットに通信できる。
- 新たに追加する場合、ルートは CIDR で指定する
ルートテーブルを操作する
ルートテーブル - Amazon Virtual Private Cloud
サブネット
VPC の中で作成するグループのこと。 VPC が持つ IP address の範囲を超えない程度に、自由にグループ化可能。
VPC が都道府県とするなら、サブネットは市区町村みたいな立ち位置。
サブネットの性質上、ルートテーブルに関連付けることにより、初めてサブネット内にトラフィックを流すことができる。
{public,private} サブネット
public サブネット
インターネットゲートウェイにルーティングされているサブネットのこと。 public サブネット内に作成された EC2 インスタンスが public ip もしくは elastic ip を持っている場合、インターネットに接続することができる。
private サブネット
インターネットゲートウェイに routing されていないサブネットのこと。 このサブネット内に EC2 インスタンスを作成しても、通常はインターネットに接続できない。 インターネットに接続するためには、NAT gateway を構築したり、インターネットゲートウェイをルートテーブルに追加する必要がある。
予約された ip address
- 10.0.0.0
- ネットワークアドレス。ネットワーク自身を表すアドレス
- 10.0.0.255
- ネットワークブロードキャストアドレス。ローカルネットワークのホスト全てに通信するためのアドレス
これ以外にも AWS が独自に予約しているアドレスが存在する。
AWS では
- AZ(Availability zone) にまたがってサブネットを構築することはできない
AWS が予約している ip address
参考
まとめ
AWS のドキュメントは入門書として優秀。 勿論周辺情報を理解するためには、別の文献や本で知識を補わないとダメだけど、AWS なら実際に手を動かしながら試せる環境があるし、概要の把握という意味では理解が進みやすい。
本当はもっと書きたかったのだけど、一旦ここまで。
ActiveRecord::Base.connection#table_exists? と ActiveRecord::Base#table_exists? の違い
イントロ
似ているメソッドで、微妙に挙動が異なり、ちょっとハマったのでメモ
違い
引数、結果をキャッシュするかどうかが違う
引数
ActiveRecord::Base.connection#table_exists?
- 引数を一つ取る
ActiveRecord::Base.connection.table_exists?("users") #=> 引数で受け取ったテーブルが存在していれば true, なかったら false
ActiveRecord::Base.table_exists?
- 引数を取らない
class User < ActiveRecord::Base end user = User.first user.class.table_exists? #=> モデルに対応したテーブルが存在していれば true, なかったら false
キャッシュするかどうか
ActiveRecord::Base.connection#table_exists?
- キャッシュしない
- 毎回 database とやり取りして、テーブルが存在するかどうかを確認するメソッド
ActiveRecord::Base.connection.table_exists?('users') #=> true ActiveRecord::Base.connection.drop_table('users') ActiveRecord::Base.connection.table_exists?('users') #=> false
ActiveRecord::Base.table_exists?
- 一度呼びだされたらキャッシュされる
- キャッシュ先は
ActiveRecord::Base.connection
- キャッシュ先は
- 一度呼びだされたらキャッシュされる
user = User.first user.class.table_exists? #=> true ActiveRecord::Base.connection.drop_table('users') user.class.table_exists? # => true # DROP TABLE `users` したのに true が返る! ActiveRecord::Base.connection.schema_cache.table_exists?('users') # => true # # * `ActiveRecord::ConnectionAdapters::SchemaCache` によってメソッド呼び出し結果が保存されている。 # * `ActiveRecord::ConnectionAdapters::SchemaCache` インスタンスは `ActiveRecord::Base.connection` のインスタンスが保持している
結論
上にも書いたとおり、引数と、メソッド呼び出しの結果をキャッシュするかどうかが違う。
ActiveRecord::Base.table_exists?
は通常ActiveRecord::Base
継承したモデル(例だとUser
)が対象となるので、引数を取らない- また、table の存在判定は、一般的には変更されにくい値であるので、一度
table_exits?
を呼び出したらキャッシュされる
と覚えれば良い。
私は動的テーブルを作ったり消したりしていてハマってしまいました。
ActiveRecord を使って、頻繁にテーブルを作成したり削除したりする場合は注意が必要。かも。
Mac で apery を compile する
イントロ
最近、職場の後輩に将棋で負けたことをきっかけに、将棋がマイブーム。
apery って?
将棋プログラムの一種。2014 年の世界大会で優勝したとかなんとか。
一部界隈では、あの ponanza 先生をも凌ぐとかなんとか言われている?らしく、とにかくすごく強いソフト。
で、そんな世界大会で優勝した将棋エンジンが github 公開されているのを知ったので、compile してみました。
そのままやると...
すさまじい警告が出て、失敗する
$ make 24 warnings generated. g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -march=native -o ../obj/common.o -c common.cpp g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -march=native -o ../obj/pieceScore.o -c pieceScore.cpp g++ -o apery ../obj/main.o ../obj/bitboard.o ../obj/init.o ../obj/mt64bit.o ../obj/position.o ../obj/evalList.o ../obj/move.o ../obj/movePicker.o ../obj/square.o ../obj/usi.o ../obj/generateMoves.o ../obj/evaluate.o ../obj/search.o ../obj/hand.o ../obj/tt.o ../obj/timeManager.o ../obj/book.o ../obj/benchmark.o ../obj/thread.o ../obj/common.o ../obj/pieceScore.o -lpthread -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -march=native ld: library not found for -lgomp clang: error: linker command failed with exit code 1 (use -v to see invocation) make: *** [apery] Error 1
gomp
というライブラリが無いと言われているようだ。
gomp とは
GOMP — An OpenMP implementation for GCC - GNU Project - Free Software Foundation (FSF)
openMP で実装している GNU project らしい。
openMP とは
複数CPU を効率的に計算するライブラリのこと。所謂スレッド。
http://www.cc.u-tokyo.ac.jp/support/kosyu/03/kosyu-openmp_c.pdf
計算を早く行うためにマルチスレッドで処理しているのだろう、と想像。
それと URI protocol の仕様として、計算中でも入力を受け取れるようにしなければならないので、そういうところでもスレッドの出番はありそう。
Mac でどう compile するか
g++-4.9 で compile する
環境
OSX 10.11.2
$ brew install gcc49
$ g++-4.9 --version g++-4.9 (Homebrew gcc49 4.9.3) 4.9.3 Copyright (C) 2015 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
--- a/src/Makefile +++ b/src/Makefile @@ -1,4 +1,4 @@ -COMPILER = g++ +COMPILER = g++-4.9 #COMPILER = mpicxx CFLAGS = -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp CFLAGS += -march=native
結果
$ cd src $ make g++-4.9 -o apery ../obj/main.o ../obj/bitboard.o ../obj/init.o ../obj/mt64bit.o ../obj/position.o ../obj/evalList.o ../obj/move.o ../obj/movePicker.o ../obj/square.o ../obj/usi.o ../obj/generateMoves.o ../obj/evaluate.o ../obj/search.o ../obj/hand.o ../obj/tt.o ../obj/timeManager.o ../obj/book.o ../obj/benchmark.o ../obj/thread.o ../obj/common.o ../obj/pieceScore.o -lpthread -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -march=native
というわけでうまくいった。
うまくいったけど、どういうことなのか
HiraokaTakuya/apery の README.md より。
Linux のディストリビューションによっては、Makefile に記述されている '-lpthread' を '-pthread' にしなければ、 実行時にエラーになってしまう場合があります。 Linux, Windows で G++ 4.8 以上のバージョンで動作確認をしています。 Clang では正しくビルド出来ているか確認出来ていません。 Visual Studio でビルドすることは現状では出来ません。 Windows でビルドする場合は、MinGW64 をお使い下さい
というわけで、g++4.9
を使うとうまくいく、と。
mac のデフォルトでは、gcc コマンドが clang コマンドの alias になるという罠があり、明示的に 4.9 以上の gcc を指定する必要があった、というオチ。
普段の生活では gcc
に馴染みがないので、少しハマった。
起動を早くする
初回起動時は評価関数生成のため、起動が非常に遅い。
ので、以下を行って評価関数のみ生成しておく。
linux,macでのコンパイルと使い方 · HiraokaTakuya/apery Wiki
$ git submodule init $ git submodule update --depth=1 # コンパイル済みの apery を bin 以下に移動させる $ cp ../src/apery . $ ls bin 20151105 Readme.txt apery book make_synthesized_eval.bat make_synthesized_eval.sh # bin の directory 上で `make_synthesized_eval.sh` を実行する。 $ cd bin ./make_synthesized_eval.sh info string start setting eval table info string end setting eval table
で成功。
make_synthesized_eval.sh
が、bin
以下で実行されること前提の実装になっていたのが難しかった。
動かしてみる
# 入力待ちになる $ ./apery # 標準入力で通信開始の合図を入れる usi # apery が標準出力でレスポンスを返してくれる id name Apery Debug Build id author Hiraoka Takuya option name Best_Book_Move type check default false option name Book_File type string default book/20150503/book.bin option name Byoyomi_Margin type spin default 500 min 0 max 2147483647 option name Clear_Hash type button option name Emergency_Base_Time type spin default 200 min 0 max 30000 option name Emergency_Move_Horizon type spin default 40 min 0 max 50 option name Emergency_Move_Time type spin default 70 min 0 max 5000 option name Eval_Dir type string default 20151105 option name Max_Book_Ply type spin default 32767 min 0 max 32767 option name Max_Random_Score_Diff type spin default 0 min 0 max 32600 option name Max_Random_Score_Diff_Ply type spin default 40 min 0 max 32767 option name Max_Threads_per_Split_Point type spin default 5 min 4 max 8 option name Min_Book_Ply type spin default 32767 min 0 max 32767 option name Min_Book_Score type spin default -180 min -32601 max 32601 option name Minimum_Thinking_Time type spin default 1500 min 0 max 2147483647 option name MultiPV type spin default 1 min 1 max 594 option name OwnBook type check default true option name Skill_Level type spin default 20 min 0 max 20 option name Slow_Mover type spin default 100 min 10 max 1000 option name Threads type spin default 4 min 1 max 64 option name Use_Sleeping_Threads type check default false option name USI_Hash type spin default 256 min 1 max 65536 option name USI_Ponder type check default true option name Write_Synthesized_Eval type check default false usiok
というわけで無事動かせた。
これで世界レベルの将棋ソフトが動かせる!!!