読者です 読者をやめる 読者になる 読者になる

パステル色な日々

気ままに綴るブログ

Jenkins 2.0おじさんとレガシー環境を駆け出していく

境遇

レガシー環境で働けているので改善活動が捗る今日この頃。 自動テストをいよいよ実行したいのでCIサポートしてくれるツールを考えてみた。 オンプレの制限があったのでJenkinsがまっさきに思い浮かんだがあまり導入にポジティブじゃなかった。 TECHNOLOGY RADARを読んであまりいい印象じゃなかったから。 とは言え課題のコード品質アップにCI環境は必須だ。 ちょうどpepaboが採用している記事を見かけたのでDrone.ioも検討したが、そのままでは利用できないのでplugin作ろうとしたが、あまりマイナーに突っ走ると周りがついてこれなくなると思ったので断念した。 そんなこんなで結局JenkinsおじさんとCIデビューすることになった。

インストー

サーバは適当に用意してOSにはCentOS7を採用した。 JenkinsはMasterとNode×2の構成にした。 Masterには実際のビルド実行環境を用意せず、Nodeにまかせることにした。 Masterの作成にはAnsible Playbookを作成した。 JenkinsのRoleは充実していてGalaxyで配布されているものをそのまま利用した。

github.com

NodeにはSSHとGitとJDK 1.8を最低限インストールしておき、Masterからの認証ができるようにしておく。 SSHを使ったNodeの追加はプラグインでサポートされているのでMasterにプラグインを導入するのを忘れずに。 JDK 1.8なのはJenkins 2.54からJava8が必須になったから。

jenkins.io

あとはNodeにビルド環境を構築すればおっけー。

Pileline as a code

CI環境を用意したらビルド時に行うこと、つまりPipelineを登録する。 Jenkins 2.0からはJenkinsfileをつかった登録方法が一般的だ。 Jenkinsfile用意してリポジトリ上で管理するとチームメンバに嫌でも目に入るし、何をやっているのかもなんとなくわかってもらえると思う。 Jenkinsfileの構文はとても簡単にできるDeclarative Pipelineとより高度な設定を記述できるScripted Pipelineが用意されている。

jenkins.io

やっていることはBuild, Test, Deploy, Lintで今のところはDeclarative Pipelineで運用している。 実行中に失敗したらRocketChatに通知するようにしている。 Declarative Pipelineでは失敗のステータスから成功に変わった時にイベントを登録する構文が用意されていないのでScripted Pipelineで解決できるなら試してみても良いかもしれない。

Jenkinsfileはリポジトリのルートにおいておくと便利だ。 Jenkinsのジョブ作成にGitHub Organization Folderを利用すると自動でJenkinsfileのあるリポジトリを見つけてJenkinsに登録してくれる。 リポジトリにWebHookを設定しておくとPush時に自動でジョブを実行してくれてCIを実現しやすくなる。 実はうまく行っていない事例としてブランチ名を xxx/yyy みたいにスラッシュを含むようにするとリポジトリスキャン時に登録できるもののPush時に自動でジョブを実行してくれないと言うものがある。

Blue Ocecan

Jenkinsの見た目にはMaterial Designを利用しているんだけど、近頃Blue Ocean 1.0がリリースされたこともあってインストールしている。

jenkins.io

見た目がモダンなデザインでGUIを利用してJenkinsfileを作成したりできるみたいだけど試せていない。 今のところは見た目のおしゃれさでしか恩恵を受けられていないんだけど、チームがJenkinsへ慣れ親しんでもらうためにGUIで色々できるようにしたい。

Jenkinsの所感

たまーにリポジトリのfetchに失敗していたりして、 git fsckgit gc をやってやらないといけない時があるのが謎だったりするのですが、今のところ問題なくコード品質の改善に一役買ってくれている。 Jenkinsはジョブの登録が自由にできるため、CIに関係ないジョブ (ansible playbook使ったサーバ構成のジョブなど) を登録できてしまうが、CIと関係のないジョブは登録しないようにしようと思った。 というのもジョブの実行にWeb APIが使えて便利だからといろいろ登録すると、何のためにとか依存関係が不透明化したジョブがたくさんできて煩雑になりそうだからだ。 Jenkinsおじさんになんでも押し付けるのではなく解決したい課題にあったツールを模索していきたいところである。

Vagrant 1.9.4 には不具合がある

vagrant up または vagrant reload をするとエラーが起こる。 エラーメッセージは次のIssueを見ていただきたい。

github.com

Issueにある通り3つのファイルをmasterブランチからダウンロードして上書きすると解決する。 vagrant provison を利用したら、さらにエラーが発生した。

github.com

vagrant plugin install vagrant-share --plugin-version 1.1.8 でバージョンアップしてあげましょう。 VagrantVirtualBox周りはまだまだ安定しないですねー。 んー微妙。

プログレッシブウェブアプリ (PWA) はいいぞ

PWA

Progressive Web Apps (PWA) の存在を知ったのは2016年のng-japanでした。

pastelinc.hatenablog.com

ずっと気になっていたんですが、最近ようやくチュートリアルをやったので書き留めておこうかなって思います。

Your First Progressive Web App

日本語翻訳版もあるんですが、サンプルアプリの変更に追従してくれてないのでこちらメインで進めていくことになりました。

PWAと言うのはGoogleの提唱する新しい概念です。そのあたりの詳しい説明は記事が溢れているので見つけて読んでいただくのが良いかと思います。先のリンクではこの概念を実装する方法が具体的に提示されているんですが、やってみるとわかったようなわからなかったような感覚に襲われます。PWA実装手段の一つAppShellモデルの考え方はわかりやすいです。ユーザー インターフェースが機能するために必要な最小限の HTML、CSSJavaScriptをオフラインでも読み込めるようにキャッシュしておき、コンテンツとなるデータを明確に分離する考え方です。

App Shell モデル  |  Web  |  Google Developers

その中でService Workerの利用を猛烈におすすめされるんですが、Service Wokerを使ったデータのキャッシュ操作がよく飲み込めませんでした。Service Wokerのライフサイクルやどういうイベントを利用できてそのイベントでは何をしているのか、知識無しで実装したことが一層わかりにくくさせていたと思います。ブラウザにもキャッシュ機能は実装されており、そちらのキャッシュを注意深く意識してコンテンツが更新されることを確かめるデバッグがやりにくかったです。

Service Workerを利用したキャッシュとの大きな違いはキャッシュできるデータをこちらが指定できることでしょうか。 またオフライン時にもキャッシュされたデータから素早くアプリを構築してユーザーに状況を問わず利用できるシーンを提供できるのはビジネスでもやる価値があると思いました。

マニフェストの利用も忘れてはいけません。マニフェストを宣言しておくとウェブアプリのインストールバナーをブラウザが表示してくれます。ホーム画面への追加はどのアプリでもできるのですがマニフェストを宣言しておくとアイコンなどをカスタマイズすることが出来ます。

新しく実装するためには Web Starter Kit を活用するのが良さそうです。また、LighthouseはPWAのチェックリストを自動でテストしてくれます (Lighthouseに実装されていないチェックリストもあります) 。 昨今のフロントエンドフレームワーク上に構築したアプリケーションなら大抵は満たせているはずです。フレームワークアーキテクチャの良し悪しを語る上でのものの見方の一つとしてPWAを考えるのも面白いかもしれません。サンプルアプリ以外もぜひぜひ実装してみたいですね。

Dockerコンテナを使った開発環境

会社でPCを買ってもらえると聞いたので、「Macbook Proがいいです。」と言ったんですが、「駄目です。」と言われました。 そういうわけでWindows上で環境構築してたんですが、如何せん何かと面倒くさいんですよね。 そんなところこんな記事を見つけました。

docker-composeを使って最高の開発環境を手に入れた

ちょうどDocker for Windowsが使えたのでDockerで環境構築を試してみることにしました。 それも全部入りのコンテナを一つ作りsshdを実行するだけの作りです。 Dockerを開発環境で利用しているという声はちらほら聞くのですがWindowsでやっているという声は聞かないので、記事にしてみます。 ただし開発環境を全部詰め込んだコンテナはイメージサイズが大きくなること必至です。 あまり良いDockerの利用例でもないと思っているのでご注意を。

Docker for Windowsをインストールしただけでは通常通りdata volumeをmountできません。 data volume上でデータ作成するとPermission ~と怒られます。 設定はこちらの記事を参照しました。

rominirani.com

またdocker-composeを使う場合yamlシンタックスに沿ってc:/Usersを含む場合はちゃんとクォートで囲ってあげることにご注意ください。 余談ですがDocker Machineの環境でdocker composeを利用する場合、パスの解決に環境変数を必要とする場合があります。

docs.docker.com

github.com

Windowsではこうしたトラブルにいちいち出くわすので大変です。

最初に参照した記事にDockerfileの例があったのでそのままお借りしてイメージを試しに作成してみました。 すると2.5GB以上のイメージが完成しました/(^o^)\

(以前書きかけだったので整えて記事にしてみました)

MeCabのRoleを作った

Ansible Galaxy

MeCab自然言語処理における形態素解析エンジン。VM上で利用しようと思ったとき真っ先に最近はAnsible GalaxyでRoleを探すんだけどMeCabのRoleがなかった。とりあえずCentOS上で利用したかったのではじめてRoleを作って登録してみた。

galaxy.ansible.com

最近はAnsibleのPlaybook作るときには自前でRoleを用意せずGalaxyを使ってRoleを再利用している。Roleの作成コストはすごく大きくてはじめのうちはどう作って良いのかわからない。GalaxyはどういうRoleの作成方法がベストなのかを教えてくれたし、再利用性によって一からRoleを作成するコストを大きく削減してくれた。
今回ははじめてRoleを作ったので、簡単にRoleの作り方を紹介する

Roleの作り方

ansible-galaxy init を実行するとRoleの雛形ができる。すでにtaskを作っているのであればコピーして書けば良い。varsやdefaultsに記述する変数は命名規則があるので参考にして欲しい。
Roleに登録するのに必須となるのがmetaデータの記述だ。通常どおりmetaデータには依存しているロールを書ける。だが今回はGalaxyに登録する情報も記述してやる必要がある。予め meta/main.yml に書かれている案内の通りメタデータを追記すればいい。出来たRoleはgithubにpushしておこう。
travisciの力を借りているのでリモートリポジトリを作成した段階でtravisci側でwatchするように設定しておくのを忘れずに。
最後にansible galaxyにサインインしてimport Roleから該当のリポジトリを選択してimportしてやり、role名を適宜変えてやれば完成だ。

いいRole

いいRoleとはどういうものかわからないけど参考にしたRoleがある。

github.com

彼のRoleはすごく参考になった。varsやdefaultsの利用方法がきっちりわけられていてディストリビューションごとの違いをうまく吸収している。
また、アプリケーションのインストール方法について書かれたRoleでは依存するDBに関するtaskを実行するか否かをユーザーが決められる猶予があるRoleもよい。

github.com

このRoleにはMongoDBが利用されているがCentOSでインストールされるのは2系だ。これではレプリケーションを組む時にエラーが起こった。バージョン選択の余地は用意されておらず途方にくれていたが、MongoDBのインストールをしないという選択肢が用意されていた。そこでMongoDBのインストールは別のRoleを使い無事にアプリケーションの起動まで出来たのだ。
ガチガチに凝り固まったRoleは再利用できてもフィットするシーンが限られる。 よいRoleは幅広い用途に耐えうる設計がされている必要があると思う。

終わりに

Ansibleはとてもいいツールだと思ってるしこれからも使っていくと思う。GalaxyへのRoleの追加も適宜やっていきたい。このRoleについてははじめてだったけど公開まで2時間くらいで出来たし (taskは予め作ってました) これからはもっと早くできると思う。
Ansibleに期待するのは状態チェックのための機能の充実だ。Check modeではサーバの状態がplaybook通りか調べることができるがインストールされている必要があるものがインストールされていないとその後の設定ファイルコピーのチェックをすっ飛ばしてしまう。部分的にtaskを実行するにはtagをつけるか実行するRoleに制限をつけるかしかないんだけどサーバへの状態チェックのためだけにやるには手間だ。このあたりが充実してくればもっと捗ると思う。

PHPでEUC-JIS-2004が使えるようになっていた

PHPEUC-JIS-2004が使えるようになっていました。
何かと話がややこしい文字コードの話題ですが少しだけ記事にしてみます。

EUC-JIS-2004 - Wikipedia

EUC-JIS-2004はJIS X 0213の符号化方式のひとつです。
次のような特徴があります。

  • コード値0x20から0x7FまではASCII (厳密にはISO/IEC 646 国際基準版) を用いる。
  • コード値0xA1から0xFEまでは、2バイトを用いてJIS X 0213の第1面を表現する。この部分はJIS X 0208の上位互換である。
  • 0x8Fに続く2バイト文字1文字分 (0xA1から0xFEまでの2バイト) は、JIS X 0213の第2面の文字である。
  • 0x8Eに続く1文字分 (0xA1から0xFEまで) は、JIS X 0201片仮名を表す。

波ダッシュと全角チルダといえばピンとくる方もいらっしゃるとおもうのですが、EUC-JPはJIS X 0212 (補助漢字) をエンコードします。
その時補助漢字は制御文字SS3 (シングルシフトスリー、0x8F) に続けて現れるので3バイトが必要になります。
Internet Explorerではこれを文字化けとして扱います。
そこで次のような変換を行ってみます。

$c = mb_convert_encoding("\x8F\xA2\xB7", 'EUC-JP-2004', 'EUC-JP');
echo bin2hex($c); // 0x7E チルダ

wikiには次のようにも書いてありました。

JIS X 0213第1面はJIS X 0208の上位互換であり、またEUC-JPにおける補助漢字は実態としてほとんど使われていないため、既存のEUC-JPの文書はほとんどの場合そのままEUC-JIS-2004の文書として扱うことができる。

EUC-JIS-2004がEUC-JPの文章をそのまま扱うことができるのであれば、補助漢字など3バイトが必要な表現もうまく表示できそうです。
これでEUC-JPなコードでもInternet Explorerで文字化けせずに表示できるのではないでしょうか。
UTF-8でコードを記述するようになって、かなり経過するのであまり出会うことがないかもしれませんが、もし出会った際には思い出してみてください。

What's new in Angular 4

お久しぶりですpatelIncです
Angular 4のリリースが迫ってきました🎉
今日は調べたことをまとめようと思います

pastelinc.github.io

先日開催された ng-kyoto meetup #5 にてオーガナイザーとして登壇してきた内容の振り返りとなります
スライドは文字少なめの構成にしたのでスライドと合わせてこの記事でAngular 4のことについて振り返っていただければと思います

Angular 4リリースに際してAngularプロジェクトがより安定したリリースを続けていくための方法として取り入れた3つのポリシーについてまずお話します
後からAngular 4の新しいところをCHANGELOG.mdにかかれていた内容に沿ってお伝えしようと思います

SemVerポリシーの導入

一つ目にAngularは2016年9月にSemantic Versioningポリシーを採用しました
SemVerについてはスライドにリンクがありますので御覧ください

  • すべてバージョン番号に意味を追加すること
  • アップグレードの理由がわかる
  • 安全にバージョンを上げることができる

SemVerポリシーの導入は以上のような方法で安定を提供します

Time-based Release Cycles

二つ目に図の通りパッチバージョンを週に1回、マイナーバージョンをメジャーバージョンのリリース後3ヶ月間、それに下位互換性のあるメジャーバージョンをリリースします
メジャーバージョンは6ヶ月に1回リリースされます。早い!!!

Deprecation Policy

最後にAPIの廃止ポリシーが定められました
AngularJSからAngular 2のバージョンアップのときに苦労された方も多いかもしれません
Breaking Changesは大きな混乱を招きますが必要なことです
Angular 4からはこれを前もって非推奨であることを開発者に知らせることである程度備えることができるように配慮してくれます

  • リリースノートで廃止予定を発表
  • 推奨されていないAPIを引き続きサポートしてくれて、更新には6か月以上の猶予があります

peer dependencies なライブラリ (バージョンを決め打ちで使っているもの) TypeScriptやRxJSやZone.jsなどの更新もSemVerのポリシー対象として扱われます
Angularアプリケーションに対するBreaking Changesでないのであればマイナーチェンジで更新もありえます

以上がAngular 4からの安定したリリース体制です
次に新しいところについてお伝えします

New View Engine

この変更がAngular 4のメインの変更だと思います
この変更は前提知識としてAOTコンパイラやTree Shakingの知識が必要です
これらの事情を省いて説明すると新しいView Engineになったのでよりファイルサイズを小さくできるようになりましたということです
AOTコンパイルについて知らない方は一度スライドでも最後に紹介している @Quramy さんの資料をご覧ください

qiita.com

docs.google.com

ここからは少し詳しく説明してみます
AngularはAOT (Ahead of time) コンパイラを提供することでbootstrap時のコンパイルの手間を大きく軽減してくれました
さらにGoogleではClosure Compilerを使うことで大幅にテンプレートサイズを小さくできていました
しかし問題としてClosure Compilerを使うことはお手軽ではなくGoogle外のユーザーにとって大きなハードルがありました
しかも最近の新しいフレームワーク (inferno.js) はAngularと同様もしくはそれ以上のパフォーマンスを発揮してテンプレートのサイズがもっと小さいものになりました
そこでAngularチームはView Engineを見直すことにしました

AngularはView Engineを定義することでDOMノードとディレクティブインスタンスを何度も反復して作成しています
AOTコンパイラはたくさんのView Engineのコードを生成します (ngfactoryファイル)
今回のチューニングではこのView Engineとして生成されるコードがより小さくなるように見直されました

驚くべきはClosure Compiler無しでおよそ3分の一までテンプレートサイズを削減できたことです
しかし131,040のバインディングのChange Detectionを計測すると従来よりも1.5倍の時間がかかり20倍のメモリを消費します
これに関してはOnPushコンポーネントを使って一部をダーティチェックレンダリングするのが良さそうです
今後OnPushをより簡単に扱える仕組みを用意することを課題に挙げていました

*ngIf 構文の拡張

<ng-template #loading>Loading...</ng-template>
<div *ngIf="userObservable | async; else loading; let user">
  {{ user.name }}
</div>

ng-japan代表の@laco0416さんがブログですでに解説されているので御覧ください

blog.lacolaco.net

  • ngIfによる条件付けと、その条件により制御されるテンプレートを分離
  • これまでは真の場合と偽の場合にそれぞれ逆の条件のngIfが必要
  • ngIfに渡された式の評価結果をローカル変数にアサインできる

@angular/animations 爆誕

@angular/animations がコアモジュールから分離しました
必要な場合だけ利用するようにしましょう
アニメーションが必要なライブラリをインストールすると自動でインストールされるようになるはずです (e.g. Material)

TypeScript 2.1に更新

AngularのベースラインのTypeScriptバージョンが1.8から2.1にバージョンアップしました
これによりngcコマンドの実行が早くなりました
加えてTypeScript compilerの最適化とより良いエラーの恩恵が受けられるようになりました

StrictNullChecks

TypeScript 2.1 が利用できるようになったことでTypeScriptのStrictNullChecksに準拠しました
つまり、必要に応じて、プロジェクトでStrictNullChecksを有効にすることができます

let foo = undefined;
foo = null; // NOT Okay
interface Member {
  name: string,
  age?: number
}

getMember()
  .then(member: Member => {
    const stringifyAge = member.age.toString() // Object is possibly 'undefined'
  })

undefinedを割り当てるのかNullを割り当てるのかが厳密になります

Angular Universal

Universalの数カ月分の作業成果がコミットされています
ドキュメントが出るようなので寝て待ちましょう
先行して確認したい方には次のリポジトリをおすすめいたします

github.com

Flat ES Modules (Flat ESM / FESM)

FESMは、パブリックAPIのみをエクスポートするESMです (example file)
これはTree Shaking時に生成されるファイルのサイズを小さくしてくれます
今のところRollupもしくはClosure Compilerが対応していてWebpackは未対応です

WebpackはTree Shakingに対応したのでは?と思っていたのですが実は他のツールと比較するとまだ完全ではなさそうです
これはAngularの開発者でもあるIgorさん (@IgorMinar) が言及していました

要するにファイルに7つのシンボルが含まれ、1つだけがインポートされると、Tree Shakingの時に7つのシンボルがすべて取り込まれるからです
おそらく他のツールは本当に必要なものしかビルドしないようになっているのだと思います

ES2015 Builds

試験的な取り組みとしてFESMをES2015の形式で提供します
試したい方はpackage.jsonの “es2015"プロパティを解決するように設定してください

調べている最中に知ったこと

NG-BEのIgorさんの公演を見て

  • Googleのサービス(Google Map…etc.)上で一度テストされてから提供される
  • WebpackやSystemJSは最高のソリューションではないと思っている
  • だからGoogleでは独自のカスタムローダーを使ってビルドしている
  • SystemJSはデモアプリに最適
  • Angular Dartとはすでに開発路線が別れており別物と思ったほうが良い
  • APIを統一しようとかそういう思想はない

Tsickle/Clutz

TsickleはTypeScriptのClosure annotated JavaScriptを生成し、ClutzはClosure annotated JavaScriptからTypeScript定義ファイルを生成します。 一緒に使用すると、クロージャ互換のコードベースでTypeScriptを使用することができ、その逆も可能らしいです

まとめ

  • Angularは安定したバージョンアップができるように環境を整備した
  • Angular 2からAngular 4のバージョンアップならお手軽にできそう
  • New View Engineをはじめとする努力でより高速にアプリケーションを提供できるようになった

スライドにあるようにこの2つが所感です
リリースサイクルについては見守るしかできませんがAngular界隈が活気づきそうですね