よちよち歩きのITエンジニアのメモ

Web技術など学んだ内容をメモしておくブログです。どんなにちっちゃくてもいいから、 一歩、ほんの小さな一歩でも夢や目標に近づくように頑張ります

【Node.js】PM2&keymetricsについてのメモ

会社のプロジェクトで、Node.jsを使うことになったので、
本番環境での運用、監視ツールとしてPM2導入の検討するためのメモ

概要

PM2・・・プロセス管理、デーモン化(オープンソース)
`Advanced, production process manager for Node.js`
http://pm2.keymetrics.io/

keymetrics・・・PM2のWeb管理、監視ツール
`Monitoring Reliability, Performance and Errors For Node.js Applications`
https://keymetrics.io/
・複数のPM2の統計データをモニタリングすることが可能
・Web上からマニュアルで再起動も可能
・Gitでのデプロイも可能

導入したい理由

(1) Express.jsのページで紹介されていること

Express アプリケーションを実動で実行する際、以下のタスクを実行するためにプロセス・マネージャー を使用すると便利です。

・アプリケーションが異常終了した場合に自動的に再始動する。
・ランタイム・パフォーマンスとリソース使用量に関するインサイトを得る。
・パフォーマンスを向上させるために設定を動的に変更する。
・クラスタリングを制御する。

Express およびその他の Node.js アプリケーション用の最も一般的なプロセス・マネージャーは次のとおりです。

・StrongLoop Process Manager
・PM2
・Forever

http://expressjs.com/ja/advanced/pm.html
より引用

(2) 有名企業での採用実績が豊富なので信頼性に期待ができる

http://pm2.keymetrics.io/users/

機能

PM2
  • プロセスのデーモン化
    • バックグラウンドで実行
  • ログ収集
    • エラーログの収集
  • クラスタリングと再起動
    • 2プロセスが起動されて、通常は1プロセスで実行されるが、障害がおきると、もう一つのプロセスに自動で切り替わって、その間に障害のあったプロセスを自動で再起動してくれる
  • 動作設定--
    • PM2で管理するプロセスについて、細かな設定が可能です。設定は、JavaScript形式、JSON形式、YAML形式をサポートします。
  • PaaS 互換
    • PM2のAPIを利用することで、さまざまなPaaS(Heroku/Google App Engine/Azure)上から、PM2との連携が可能です。
  • 監視とリロード
    • アプリケーションのファイルやディレクトリの変更を検知して、自動的にアプリケーションを再起動できます。
  • ログ管理
    • リアルタイムログの確認や、JSON形式での情報取得、ログローテーションなどが利用できます。
  • モニタリング
    • プロセスごとのCPU/メモリ使用率、メタデータ、グローバルログの確認ができます。
  • 最大メモリ制限
    • 設定した上限メモリ値を超えたプロセスを自動で再起動させることが可能です。
  • クラスタモード
    • Node.jsアプリケーションプロセスを全CPU、全CPU - 1、特定CPUに割り当てたりすることが可能です。
  • ホットリロード
    • reloadコマンドにより、プロセスのダウンタイム0秒を実現できます。
  • 開発者モード
    • 開発者向けに開発モード(ファイルの変更に応じたリスタートに対応など)でアプリケーションを起動させることが可能です。
  • 起動スクリプト
    • 起動システム(systemd、upstart、launched、rcd、systemv)に応じた起動スクリプトが提供されます。

http://openstandia.jp/oss_info/pm2/
より抜粋

Keymetrics
  • モニタリング

- Keymetricsと連携させることにより、複数のPM2の統計データをモニタリングすることが可能になります。

  • Git連携

- git と連携したデプロイが可能です。

foreverとの比較

nodejs用だと、foreverとPM2が有名だが、Keymetricsなど本番運用を想定したWebツールを利用することができない。

コマンド


## 通常
$ pm2 start app.js

## 開発モード
$ pm2 start app.js --watch


## リアルタイムモニター
$ pm2 monit


## 各種リンク

phpの最大値と最小値

忘れやすいのでメモ。

PHPでINTの最小値、最大値を出すためには以下の定数を使えば良い
最小値:PHP_INT_MIN
最大値:PHP_INT_MAX


PHP: 整数 - Manual

整数のサイズは定数 PHP_INT_SIZE で、 そして整数の最大値は定数 PHP_INT_MAX でそれぞれ決まります。 これらの定数は、PHP 4.4.0 以降および PHP 5.0.5 以降で使えます。 PHP 7.0.0 以降では、整数の最小値を表す定数 PHP_INT_MIN が使えるようになりました。

【入門】【Mac】Geb+SpockではじめるWeb自動テスト(Mac版) / [Introduction] Let's start Web Browser Automation Testing using Geb, Spock and Groovy(For Mac User).

【入門】Geb+SpockではじめるWeb自動テスト / [Introduction] Let's start Web Browser Automation Testing using Geb, Spock and Groovy

著者:ふじさわゆうき
Author: Yuki Fujisawa

更新日:2016/11/13
Updated date:2016/11/13

目次 / Table of contents

  1. Gebとは / What's Geb ?
  2. Gebのメリット / Why we have to use Geb ?
  3. 開発環境構築(IntelliJ IDEA) / Development Environment Building (IntelliJ IDEA)
  4. サンプルプログラム実装(Geb+Spock+Maven) / Sample program implementation (Geb + Spock + Maven)

1. Gebとは / What's Geb ?

  • Groovy言語で書かれたWebテスト自動化フレームワーク / Web test automation framework written in Groovy language
  • SeleniumWebDriverで挙がっている問題(例えば、ログインボタンを押すだけでもおおくの記述が必要など)を解決している / Geb solved Selenium Web Driver problems , for example we need only even many description press the login button

2. Gebのメリット / Why we have to use Geb ?

  • WebDriverと比較して、より短く、よりわかりやすいテストを記述することができる。Gebの提供するナビゲーターAPI(Navigator API)というjQueryのようなAPIがそれを可能にしている / Compared to WebDriver, shorter, and can be described more meaningful test. Navigator API like jQuery is allow it
  • Page Object patternをサポートしているので画面変更に強いテストを作成することができる / Since Page Object supports pattern, it is possible to create a test that we can handle screen change.
  • Mavenで提供されるのでテスト作成の環境構築が簡単にできる / It is possible to easily environment construction of test creation because it is provided by Maven
  • GroovyなのでJavaと互換性があり、SeleniumWebDriverの既存資産をそのまま利用することができる / Since using Groovy has Java-compatible, it is possible to directly utilize existing SeleniumWebDriver's assets
  • Moduleを使うことで共通部分を部品化することができる / By using the Module, it can be part of a common portion

3. 開発環境構築(IntelliJ IDEA) / Development Environment Building (IntelliJ IDEA)

Java JDK 8のインストール / Installation of Java JDK 8

$ brew update && brew cleanup
$ brew cask install java
$ vi ~/.bash_profile
JAVA_HOMEを追記する
↓
# JAVA_HOME
export JAVA_HOME="/usr/libexec/java_home -v 1.8"

IntelliJ IDEAのインストール / Installation of IntelliJ IDEA

本家サイトからダウンロード&イントールする
IntelliJ IDEA the Java IDE

Firefoxのインストール

Firefox47以上のバージョンだと動作しなかったので、45.4.0esrをインストールする
Directory Listing: /pub/firefox/releases/45.4.0esr/mac/ja-JP-mac/

2016/09/20 リリースの不具合修正版で安定して動作する
Firefox 45.4.0 延長サポート版 (ESR) リリースノート

webdriverのインストール

$ brew install geckodriver
$ brew install chromedriver

4. サンプルプログラム実装(Geb+Spock+Maven) / Sample program implementation (Geb + Spock + Maven)

IntelliJ IDEA起動 / Start IntelliJ IDEA

$ open /Applications/IntelliJ\ IDEA\ CE.app

GoogleWikipediaTest Projectの新規作成とMavenの設定 / GoogleWikipediaTest Project New Create and setting of Maven

Mavenプロジェクトの作成 / Create New Maven Project

f:id:yfj2:20161106101741p:plain
f:id:yfj2:20161106101948p:plain
f:id:yfj2:20161106102033p:plain

pom.xmlの編集 / setting of pom.xml
  • GoogleWikipediaTest/pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>mygroup</groupId>
    <artifactId>GoogleWikipediaTest</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>GoogleWikipediaTest</name>
    <properties>
        <groovyVersion>2.4.7</groovyVersion>
        <seleniumVersion>3.0.1</seleniumVersion>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>${groovyVersion}</version>
        </dependency>
        <dependency>
            <groupId>org.spockframework</groupId>
            <artifactId>spock-core</artifactId>
            <version>1.1-groovy-2.4-rc-3</version>
        </dependency>
        <dependency>
            <groupId>org.gebish</groupId>
            <artifactId>geb-spock</artifactId>
            <version>0.13.1</version>
        </dependency>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-firefox-driver</artifactId>
            <version>${seleniumVersion}</version>
        </dependency>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-support</artifactId>
            <version>${seleniumVersion}</version>
        </dependency>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-chrome-driver</artifactId>
            <version>${seleniumVersion}</version>
        </dependency>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-ie-driver</artifactId>
            <version>${seleniumVersion}</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.18</version>
                <configuration>
                    <includes>
                        <include>**/*Test.class</include>
                        <include>**/*Spec.class</include>
                    </includes>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <encoding>UTF-8</encoding>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.gmavenplus</groupId>
                <artifactId>gmavenplus-plugin</artifactId>
                <version>1.5</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>addSources</goal>
                            <goal>addTestSources</goal>
                            <goal>generateStubs</goal>
                            <goal>compile</goal>
                            <goal>testGenerateStubs</goal>
                            <goal>testCompile</goal>
                            <goal>removeStubs</goal>
                            <goal>removeTestStubs</goal>
                        </goals>
                        <configuration>
                            <sourceEncoding>UTF-8</sourceEncoding>
                        </configuration>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>org.codehaus.groovy</groupId>
                        <artifactId>groovy-all</artifactId>
                        <version>${groovyVersion}</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
        <pluginManagement>
            <plugins>
                <!--This plugin's configuration is used to store Eclipse m2e settings
                    only. It has no influence on the Maven build itself. -->
                <plugin>
                    <groupId>org.eclipse.m2e</groupId>
                    <artifactId>lifecycle-mapping</artifactId>
                    <version>1.0.0</version>
                    <configuration>
                        <lifecycleMappingMetadata>
                            <pluginExecutions>
                                <pluginExecution>
                                    <pluginExecutionFilter>
                                        <groupId>org.codehaus.gmavenplus</groupId>
                                        <artifactId>gmavenplus-plugin</artifactId>
                                        <versionRange>
                                            [1.5,)
                                        </versionRange>
                                        <goals>
                                            <goal>addSources</goal>
                                            <goal>addTestSources</goal>
                                            <goal>generateStubs</goal>
                                            <goal>compile</goal>
                                            <goal>testGenerateStubs</goal>
                                            <goal>testCompile</goal>
                                            <goal>removeStubs</goal>
                                            <goal>removeTestStubs</goal>
                                        </goals>
                                    </pluginExecutionFilter>
                                </pluginExecution>
                            </pluginExecutions>
                        </lifecycleMappingMetadata>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

Gebスクリプトの作成 / Creating Geb script

下記のようなフォルダとファイルを作成します / Create a folder and files, such as the following
  • GoogleWikipediaTest/src/main/groovy/GoogleWikipediaMain.groovy
  • GoogleWikipediaTest/src/main/groovy/module/GoogleSearchModule.groovy
  • GoogleWikipediaTest/src/main/groovy/page/GoogleHomePage.groovy
  • GoogleWikipediaTest/src/main/groovy/page/GoogleResultsPage.groovy
  • GoogleWikipediaTest/src/main/groovy/page/WikipediaPage.groovy
  • GoogleWikipediaTest/src/test/groovy

f:id:yfj2:20161113114007p:plain

src/main/groovyを"Sources Root", src/test/groovyを"Test Sources Root"にする

f:id:yfj2:20161106110941p:plain

  • src/main/groovy/GoogleWikipediaMain.groovy
import geb.Browser
import page.GoogleHomePage
import page.GoogleResultsPage

Browser.drive {
	to GoogleHomePage
	search.field.value("wikipedia")
	waitFor { at GoogleResultsPage }
	firstResultLink.click()
}
  • src/main/groovy/module/GoogleSearchModule.groovy
package module

import geb.Module

class GoogleSearchModule extends Module {
	// a parameterised value set when the module is included
	def buttonValue

	// the content DSL
	static content = {
		// name the search input control “field”, defining it with the jQuery like navigator
		field { $("input", name: "q") }
	}
}
  • src/main/groovy/page/GoogleHomePage.groovy
package page

import geb.Page
import module.GoogleSearchModule

class GoogleHomePage extends Page {

	// pages can define their location, either absolutely or relative to a base
	static url = "http://google.com/ncr"

	// “at checkers” allow verifying that the browser is at the expected page
	static at = { title == "Google" }

	static content = {
		// include the previously defined module
		search { module GoogleSearchModule, buttonValue: "Google Search" }
	}
}
  • src/main/groovy/page/GoogleResultsPage.groovy
package page

import geb.Page
import module.GoogleSearchModule

class GoogleResultsPage extends Page {
    static at = { title.endsWith "Google Search" }
    static content = {
        // reuse our previously defined module
        search { module GoogleSearchModule }

        // content definitions can compose and build from other definitions
        results { $("div.g") }

        resultLinks { results.find("a") }

        firstResultLink {
            resultLinks[0]
        }
    }
}
  • src/main/groovy/page/WikipediaPage.groovy
package page

import geb.Page

class WikipediaPage extends Page {
	static at = { title == "Wikipedia" }
}

Gebの実行 / Execution of Geb

f:id:yfj2:20161113104443p:plain

Spockの実装 / Creating spock script

  • 下記のようなフォルダとファイルを作成します / Create a folder and files, such as the following
    • GoogleWikipediaTest/src/test/groovy/GoogleWikipediaMainTest.groovy

f:id:yfj2:20161113114110p:plain

  • GoogleWikipediaMainTest.groovy
import geb.spock.GebSpec
import page.GoogleHomePage
import page.GoogleResultsPage
import page.WikipediaPage

class GoogleWikipediaMainTest extends GebSpec {

	def "first result for wikipedia search should be wikipedia"() {
		given:
		to GoogleHomePage

		expect:
		at GoogleHomePage

		when:
		search.field.value("wikipedia")

		then:
		waitFor { at GoogleResultsPage }

		and:
		firstResultLink.text() == "Wikipedia"

		when:
		firstResultLink.click()

		then:
		waitFor { at WikipediaPage }
	}
}

Spockの実行 / Execution of Geb

f:id:yfj2:20161113104820p:plain

  • テストが成功すればOK / If the test is successful OK

5. クロスブラウザテストの設定と実行 / Cross-browser test setting and running

フォルダとファイルを作成します / Create a folder and files, such as the following

  • GoogleWikipediaTest/src/main/resources/GebConfig.groovy
//choose "firefox", "chrome"
driver = "chrome"

//$ brew install geckodriver
System.setProperty("webdriver.gecko.driver", "/usr/local/Cellar/geckodriver/0.11.1/bin/geckodriver")

//$ brew install chromedriver
System.setProperty("webdriver.chrome.driver", "/usr/local/Cellar/chromedriver/2.25/bin/chromedriver")

実行するブラウザの選択

  • firefoxの場合
driver = "firefox"
  • chromeの場合
driver = "chrome"

PHPカンファレンス2016に参加してきました

本日は、PHPカンファレンス2016に参加してきましたので
そのレポートです。
phpcon.php.gr.jp

講演スライドまとめ

講演スライドを見たい方は以下、ページを参照してください。
順次掲載されるとのことです。

【速報!】PHPカンファレンス2016 講演スライドまとめ #phpcon2016

参加した講演

私が参加してきたのは、以下の講演です。

10:50 - 11:30
老舗メディアが生き残るために継続的な改善に取り組んでいる話
株式会社VOYAGE GROUP
駒崎 大輔

13:00 - 14:00
Cygamesを支えるPHPと、その高速化の取り組み
株式会社Cygames
小笠原 空宙

14:20 - 14:50
PHPアプリケーションに関する12の事実
株式会社mediba
北田 翼

15:00 - 15:30
未来のWebに欠かせないREST APIを
ApacheSolr + Drupalで実装しよう
株式会社KDDIウェブコミュニケーションズ
阿部正幸

10:50 - 11:30 老舗メディアが生き残るために継続的な改善に取り組んでいる話

SVNからGitに移行してリリース物とコミット物の混乱した問題を改善した

  • チームのリポジトリ管理をsvnからGitに移行
  • コミットされたものがリリース物ではなく、辛かったがその問題が解決した
  • Gitによってレビューが活発になった。
  • デザイナーチームのフォローを厚くした結果、デザイナーチームもsvnからGitに移行することができた
  • Web制作者のためのGitHubの教科書、という本を使って布教したらしい

phpdotenvによる環境により異なる変数の問題解決

  • phpdotenvを使って、環境変数に色々と記載。これを使うまでは、パスワードがハードコードされていた。一番の利用理由は、環境によって異なるものがハードコーディングされていると辛いから
  • phpdotenvを使うと、どの環境でも共通の方法で環境変数を参照できるようになる

リリースフローの整備と自動化によるリリース品質とサイクルの改善

  • リリースフローは、コマンド実行からJenkinsに移行して、リリースフローの整備と自動化を実現した
  • この改善により、リリーススピードのアップと、小さいリリースができるようになった。

機能数とテーブルの削減による品質の改善

  • 機能数:1800->1200 , テーブル数:1200->900に削減した。機能数で600、テーブル数で300の削減はかなりの改善!
  • 機能数を減らした方法は、機能の棚卸
    • (1)機能とテーブルの一覧・・・一つ一つ調査して泥臭く作った。100万行のコードを調査するのが辛かった
    • (2)テーブルと機能の関連を調べる・・・接続ライブラリにログを仕込んで調査
  • 機能の棚卸でまとめた結果をもとに、使われていない機能とそれに紐づく、テーブル等の削除など泥臭くやることで大幅にと削減された

改善習慣を身につけることが大切。そのためには日常業務に改善の習慣を身につけるプロセスを組み込むことが必要

  • メルカリの取り組みを参考にKAIZEN会を開催
  • 丸1日、缶詰状態でエンジニアが全員、取り組む
  • 題材は、基本的に自由
    • お昼もお弁当
    • KAIZEN会の頻度は月に1回
  • KAIZEN会はエンジニアから好評
    • エンジニアとしては、集中して作業できて良い
    • 過去に自分が書いたコードをリファクタリングする時間ができた
    • 普段、見ないコードを見ることができた
    • 特にビジネス側から声を掛けられないので集中できるのは良い
    • ロジックの共通化が進んで、6000行のコードが1700行に減った事例もあったとのこと
  • KAIZEN会は8ヶ月継続中

読書会もやっている

  • 読書会も開いていて、@t_wadaさんが技術講師を務めているらしい!

まとめ

  • SVN->Git、Jenkinsによるリリースフローの自動化により、小さく素早いリリースできるようになった
    • 機能とテーブルを削減することで、不要なコードを減らして過去負債を減らした
    • KAIZEN会実施による改善習慣の定着化
  • VOYAGE GROUP様の取り組みで、技術力評価会というものも面白いなーと思いました。KAIZEN会、技術力評価会と良い取り組みが色々とあってすごいです。ぜひ、参考にします。

techlog.voyagegroup.com

13:00 - 14:00 Cygamesを支えるPHPと、その高速化の取り組み

f:id:yfj2:20161103165325j:plain

プレゼン構成

  • 前半は、サーバー構成やら取り組みやら、メンバーのマインドセットなど。後半は、Zephirを利用して試みた高速化について得られた知見についてが中心

秒間5万アクセス、100万クエリを日々処理している

  • 1200万人ユーザーが使うグラブルの話し。高速化、負荷分散については、かなりのノウハウがありそう(苦労ともいえる)
  • 1日300万人がプレイしているらしい(すげー)。秒間5万アクセス、100万クエリ、1日60GBのログがサーバーにたまる

Cygames Researchを設立

  • 2016年4月からCygames Researchを設立。
  • CySQLを開発中。ゲームに適したSQLとのこと。MySQLの10倍から20倍も速くなるとか

codeiq.jp

サーバー構成図

f:id:yfj2:20161103183010j:plain

開発環境

  • 開発環境としては、VagrantとAnsibleですぐに取りかかれる体制

モニタリングツール

  • モニタリングツールは、MuninとMackerelを使っている

ログ系

  • ログ系は、NewRelic、Google BigQueryで検索できるようにして、Fluentdでログ収集

スローガンは「面白くなければ意味がない」

  • スローガンは「面白くなければ意味がない」
  • 何を持って面白いとするのかは、ユーザー次第・・・。なのでゴールは手探り、トライアンドエラーをやりやすい実装や仕組みを整えるように意識している

ユーザーが最終的に面白いを決めるからCS優先の体制

  • CS最優先・・・ユーザーが最終的に面白いを決めるから。
    • 即顧客対応できるように、ログの収集と分析、可視化ツールを優先。確信を持って顧客に説明できるようにする

当たり前のことを当たり前にやろう

  • 当たり前のことを当たり前にやる・・・不要な処理は書かない、などなど。チームとして継続して実施することが重要。例えば、夜中にアラートがあったら、ちょっとしたことで治ってしまったり。基本的なミスをえらせば、そういうことも少なくなる。
  • チームレベルのアップがないと、チームの共通認識がなく無駄なコミュニケーションが増えるなど、人は増えたのに開発スピードが上がらないということが起こる。

New relicは最強

  • New relicは最強。もう他のサービスには戻れない。重いクエリがすぐにわかるので、毎日、地道に対応

4.5秒以上かかったリクエストは重いリクエストとして対応

  • 4.5秒以上かかったリクエストは、重いリクエストと判断
  • 日次で開発環境で実行された全クエリを監視している。問題があれば、開発者に通知する仕組み。その問題が無くならないと、デプロイできない仕組みになっている
  • 本番環境で実行されたクエリも監視。テスト、開発では問題なかったロジックでも、本番データが入ってくると想定外のことが起こる場合がちょくちょくある
  • Twemproxyでキャッシュは分散。導入してから大きな問題は起こっていない

必要なくなったデータは、順次パージする

  • 必要なくなったデータは、順次パージする仕組み
  • イベントごとにテーブルを作成して、イベントが終われば、それらのテーブルdrop Tableする

リリース前には職種、チーム問わず、レビュー

  • リリース前には職種、チーム問わず、レビューする。
  • 開発チームが気づかない問題(機能的なメリットが少ないなど)に気づくことができる

今後の新しい取り組み

  • ゲーム特有の問題に対応していきたい
  • 例えば、処理は成功して、戻り値もいいのに問題がある。キャラからして、セリフがおかしいなどがあるとそれはロジック的には正しくてもゲーム的にはNG
    • キャラのセリフを解析しておいて、過去と比較してコメントがおかしければアラートするなどの仕組みがアイディアとして上がっている

前半のまとめ

  • 結局のところ、高速化の実現は、日々の分析とそれの改善、対応を地道に繰り返すことで実現している

Zephirが面白い

  • Zephirが面白いよ。という話がでてきた。高速フレームワークのPhalconは、Zephirで実装されているので速度という意味で実績がある
  • Zephirは、PHP Likeな文法で、コンパイルするとC言語に変換してくれる
  • 実行は、C言語として行われるので、実行速度が速くなる。特に配列周りは実行速度が速い。*.soファイルなので、いろいろな言語で利用することもできる。
  • 配列が多様されているところも、PHPは配列が遅いので80%程度、速度を改善することができる

Zephir、面白いけど、コンパイル手順が増えるのがディメリット

  • Zephir、面白いけど、コンパイル手順が増えるので、新しいコードなどには使わないほうが良さそう。バグが多い、新規のコードになるとコンパイルしてから適用になるのでデプロイまでが大変。
  • 共通ロジックで、変更が入らないコードを対象とするのが良い

togetterのまとめ記事

togetter.com

14:20 - 14:50 PHPアプリケーションに関する12の事実

f:id:yfj2:20161103183302j:plain

12の事実とはTwelve-Factor Appの12の条文のこと

以下、The Twelve-Factor App の解説 - ワザノバ | wazanovaより引用

I. Codebase — One codebase tracked in revision control, many deploys
 コードベースはソース管理システムに置き、多くの環境にデプロイできるようにしておくこと。

II. Dependencies — Explicitly declare and isolate dependencies
 依存するライブラリは明確に宣言し、コードをデプロイするときは正しいバージョンがダウンロードされ、正しい場所に置かれるように設定しておくこと。

III. Config — Store config in the environment
 設定条件はソースコードの中で環境別に管理すること。

IV. Backing Services — Treat backing services as attached resources
 コードは多くのサービス(DB、キャッシュ、メール、キューなど)とやり取りし、そのサービスは様々な環境(同じマシン、別のホスト、別のデータセンター、クラウドなど)で実行されているかもしれないが、コードはその違いを意識せずに各サービスをシンプルなエンドポイント(URL、ときにはID/パスワード)で参照できるようにしておくこと。

V. Build, release, run — Strictly separate build and run stages
 ビルドする時点では開発者はあらゆる面倒な作業が必要となる。しかしリリース後、本番の実行されるステージでは、とにかくシンプルで安心できる環境を用意すること。例えば、マシンに障害があっても、アプリが自動的に再起動することで、人の手を借りないで済むようにしておくと、開発チームは安心して夜寝られるようになる。

VI. Processes — Execute the app as one or more stateless processes
 多くのトラフィックをさばき、障害耐性を持たせるために、アプリは複数のサーバで実行されることになるが、各コードを実行するインスタンスはステートレスであるべき。つまり、そのシステムのステートは、各々の実行されているアプリのインスタンスではなく、データベース及び共有されたストレージで定義されるべき。例えば、プロファイルの入力画面が3ページあり、中間のステートが実行中のコードで保持されていると、作業が完了するまで同じユーザには同じサーバがアサインされ続ける。正しいアプローチとしては、中間データがDBもしくはkey/valueストアに保持される仕組みにしておくと、途中でサーバが落ちても、ユーザは別のサーバが難なく対応してくれるようになる。

VII. Port binding — Export services via port binding
 これは IV. Backing Services の拡張的な話で、アプリは外界に対してもシンプルなURLのインターフェースをもつべきということ。ウェブサーバを使っているとデフォルトでその状態にはなっているが、例えば、社内と社外に対して共通のAPIをアプリが提供していた場合、別々のURLを用意することで、より信頼できる社内アクセスには、セキュリティレベルの違う、早いアクセスを提供できるかもしれない。

VIII. Concurrency — Scale out via the process model
 コードを実行する際に、個別の細かいニーズに対して多くのプロセスを走らせるとよいというアイデアに行きつくはず。例えば、ウェブリクエストの対応、APIコールの対応、バックグランドで入会のwelcomeメールやtweetの送信など、それらの作業が独立して別々のプロセスで平行して実行できるようになると、アプリはうまくスケールする。

IX. Disposability — Maximize robustness with fast startup and graceful shutdown
 最近は外部ライブラリへの依存が多くなってきているので、秒速で起動することは難しくはなっているが、コードの読込み以外に、その都度に発生する作業があると、高頻度でのリリースサイクルづくりが難しくなる。本番のトラフィックにすぐに対応できるように事前に準備をしておき、起動プロセスをすっきりさせること。また、クラッシュも避けたいが、クラッシュした場合もすぐに復旧できるようにしておき、都度クリーンアップ作業が発生するような状態は避けたい。

X. Dev/prod parity — Keep development, staging, and production as similar as possible
 開発/ステージング/本番を極力同じ環境にしておくこと。

XI. Logs — Treat logs as event streams
 最低限、エラーログはNew RelicやAirBrakeに送ったり、ログをpapertrailやSplunk Stormに送るようにしておくこと。リアルタイムのログデータ収集、長期のアーカイブ、データマイニングをHadoopなどを利用して構築しておくと尚良し。

XII. Admin processes — Run admin/management tasks as one-off processes
 アプリが本番に提供されると、悪いデータのクリーンアップや、分析データの集計、A/Bテストの実施など、一時的なタスクを開発者が実行しなくてはいけなくなる。ローカルのターミナルウィンドウで実行したり、データベースを直接アップデートはしないこと。本番環境のマシンから実行すること。本番システムへのコンソールアクセスを用意するのは必須。

Twelve-Factor Appを実現

  • Twelve-Factor Appを実現したというプレゼン
  • Twelve-Factor Appを知っている人は、会場にはほぼ無し

環境変数として外だししてやることが重要

  • 環境によって変わるものは、config.phpなどに格納するのではなく、環境変数として外だししてやることが重要。下記、ルールがそれにあたる
  • 環境変数の実現は、AWS CloudFormationを使って実現。環境変数は、HOST_NAMEだとか、そういうところ。PHPアプリケーション、Webサーバーのhttped.confの各値とか

Twelve-Factor Appはエンジニアとしては学習コストは大きいが、やる価値はある

  • エンジニアとしては学習コストは大きいが、やる価値はあるよ。でも、実運用はこれからだから、実運用も含めた成果がわかるのはこれからということ

togetterのまとめ記事

togetter.com

15:00 - 15:30 未来のWebに欠かせないREST APIをApacheSolr + Drupalで実装しよう

f:id:yfj2:20161103183631j:plain

ApacheSolr + Drupalは実績のある実装方法

  • ApacheSolr + Drupalという実装は、ANNAI株式会社にて、実績のあるAPI実装方法とのこと
  • 最新だとElasticsearch + Drupalという実装らしい

システム構成

f:id:yfj2:20161103183641j:plain

REST APIサーバーで一元管理すれば、様々なシステムに対応できる

  • 一つのいろいろなコンテンツ、システムがあって、それを管理するのが大変。それを、REST APIサーバーで一元管理して、すべてのサイトに配信したらいいじゃんというのがコアなアイディア

Drupal8の記事

FESSという検索エンジンが優れている

togetterのまとめ記事

togetter.com

PhpStormでCodeIgniterを扱えるように拡張する

PhpStormでCodeIgniterを扱えるように拡張する

著者: ふじさわゆうき

更新日: 2016/10/13

PhpStormの試用期間が終わったのですが、PhpStormの便利さに負けてライセンスを購入したふじさわゆうきです。
PhpStormでCodeIgniterを扱えるように拡張する方法をメモとして残しておきます。

見つけ次第、追加更新しようかと思います。

autocompleteが効くようにする

短縮キーを登録する

神経言語プログラミング(NLP)とは何か

神経言語プログラミング(NLP)とは何か

著者:ふじさわゆうき

更新日:2016/10/12

システムエンジニアをしていると精神的に病んできたり、落ち込んだりすることがあります。そのような状態を放っておくと、集中力にも支障をきたし、仕事の成果がでなくなり、さらに精神的に病んでいくという悪循環に陥ってしまいます。私自身もそういう経験があり、その時に役に立ったのが今回紹介する神経言語プログラミング(NLP)です。記事を読んでみて、興味が湧きましたら、ぜひ、神経言語プログラミング(NLP)を学んでポジティブシンキングを手に入れてください!!

背景

  • システムエンジニアをしていると精神的に病んできたり、落ち込んだりする
  • その問題を解決したい!!
  • 神経言語プログラミング(NLP)っていいんじゃない?
  • だって、プログラミングなんだからプログラマの得意技でしょ!!
  • というわけで神経言語プログラミング(NLP)について学んでみました

神経言語プログラミング(NLP)とは

ネガティブな思考をポジティブな思考に変える方法のフレームワークのこと。心理療法のひとつ。

  • 身体の使い方を変えることで考え方を変えていく、つまり「身体 => 思考 => 行動」というのがNLPの第一の基礎
    • 「身体の使い方を変える(プログラミング) => ポジティブな思考に変える」というイメージ
    • ネガティブになりやすい体の姿勢を、ポジティブになりやすい体の姿勢に修正すればポジティブな思考に変わっていく
    • 例えば、猫背で、下を向いているとネガティブな思考になるが、背筋を伸ばして、上を向いているとポジティブな思考になるとか
  • ネガティブな言葉をポジティブな言葉に変換することでポジティブな思考に変える、つまり、「言葉 => 思考 => 行動」というのがNLPの第二の基礎
    • 例えば、「消極的 → 思慮深い」とか、「せっかち → 行動的」とか、「こだわりが強い → 信念がある」など
  • ネガティブな信念を再検討し、ポジティブな信念に変えるか、その信念を捨ててしまうことが第三の基礎
    • 例えば、「私は人前でプレゼンすると常に失敗する」のようなネガティブ信念があった場合、「"常に"ってそうだっけ?成功したプレゼンもあったよね?」と再検討してみて、そういう経験が一つでもあれば、そのネガティブ信念は嘘だとして、成功した時の場面を思い出してして「私は人前でプレゼンしたときに○○すれば成功する」のようなポジティブな信念に変えるなど

実績

  • ベトナム戦争の帰還兵の為に使われNLPは大きな効果を発揮した
  • アフガニスタン紛争で、兵隊の精神的なケアの為にNLPは使われている
  • オバマ大統領、クリントン元大統領もNLPを使っていて、コーチングを受ける目的で、5人のNLPのトレーナーを雇っている

など。他にもプロスポーツ選手が学んだりしているようです。

オススメの書籍

興味を持ったら、とりあえず読んでみてください。以下、オススメの書籍です。

MVCパターン再考

MVCパターン再考

著者: ふじさわゆうき

更新日: 2016/10/14

背景

Java, Groovy, C++, C#などいろいろな言語使ってアプリケーションを作成するなかで、MVCパターンを常に意識して開発してきました。
自分的な解釈だと、上記のような大雑把の分類です。

  • Model: ビジネスロジック、データベース処理、データオブジェクトなど
  • View: 画面出力
  • Controller: ViewとModelの仲介役、ユーザーの入力をModelに渡すなど

しかし、あるセミナーで「ネイティブアプリでは、MVCは合わない」という話を聞き、改めて、MVCがどこまで適用できるものなのか、そもそもMVCってなんだろう?と再考したくなりました。というわけで、MVCModelを再考してみます。

MVCと一言で言っても・・・

改めて調べて分かったのですが、一口にMVCといっても、以下、分類があることがわかりました

  1. MVC1
  2. MVC2
    1. Pull-MVC
    2. Push-MVC

MVC1(Smalltalk MVCとも呼ぶ)

f:id:yfj2:20161007162640p:plain
http://www.slideshare.net/about_hiroppy/mvc-39079770より参照

  1. Modelに対して変更があったときに情報を受け取りたいViewを登録する
  2. 変更されたら登録されたすべてのViewに対して通知を行う

MVC2

  • 1998年 JSP仕様のドラフトで提唱された。MVC1をWebサービスに適応させたもの
  • サーバー側からいきなりModelの状態変更が 通知されることはHTTPがステートレスなのでできない
  • Modelの状態変更は、Controllerを経由してViewへの通知するように修正された
  • WebアプリにおいてのMVCとはMVC2のことを指す

f:id:yfj2:20161007111705p:plain
http://www.slideshare.net/about_hiroppy/mvc-39079770より参照

  1. クライアントからのリクエスト(URL)
  2. リクエストを通知
  3. 結果を返す
  4. 結果を反映させる
  5. レスポンス
Push-MVC(MVC2)
  • ほとんどのMVCフレームワークは、Pull-MVCのアーキテクチャにしたがっている
  • このようなフレームワークは、処理を要求するアクションを実行し、次に結果を出力するためにデータを表示のレイヤにプッシュする。Struts、Django、Ruby on Rails、Spring Frameworkの一部であるSpring MVCなどがこのアーキテクチャの良い例
Pull-MVC(MVC2)
  • Push-MVCに対するアーキテクチャで、「コンポーネント型」とも呼ばれている
  • 「コンポーネント型」は表示レイヤから処理を開始し、必要に応じて複数のコントローラからの処理の結果を「プル」する
  • 「コンポーネント型」では、複数のControllerが一つのViewに関連付けられる。 Tapestry、Velocity などがプル型アーキテクチャの一例である

メリット

  1. ViewとModelでの並行開発が可能となる
    • ViewとModelが分離されており、それぞれの変更の影響を受けないため
  2. Modelを機能別に分けることで、テストがしやすく再利用性が高いコンポーネントを作成することができる
  3. ViewとModelの相互参照を避けることができるのでコードの見通しが良くなり、影響範囲も限定しやすい

上記メリットと実際の差異

ViewとModel、Controllerの並行開発はなかなか難しい

  1. UIが複雑に、またビジュアルで応答性を高めるほど、ユーザー入力がViewに依存して制御されるようになるため(UIが複雑になるとjQuery等のフロントエンド側のコーディングで頑張ることになるから)、ViewとControllerの結合が強くなり、ViewやControllerが単独で交換可能にならなくなる。
    • 例えば、ECサイトで"配送日を指定する"を選択した場合、日時指定のカレンダーが表示され、"配送日を指定しない"を選択すると"配送予定日が表示される"ような画面があると、配送日の選択状態によって、Viewを変える必要がでてくる。
    • この場合、Controllerは、Viewの配送日の選択状態によって、配送予定日を計算するModelに依頼するのか、配送可能日を取得するModelに依頼するのかが変わってくる(このケースだと、javascript側でのController制御になる)
    • しかし、UIが複雑だとUIの修正に合わせて、Controllerの修正も変更しなければならない可能性が高くなる。
    • このようなケースだと、クライアント側でのControllerが実装されるため、ViewとControllerの分離が難しくなる
    • このようなM-VCとなるような構造をDocument-Viewと呼ぶらしい
  2. View、Model、Controllerはそれぞれ相互依存してくることが多い。Viewの実装によって、Modelのレスポンスは影響を受けるし、逆にModelの実装によってもViewの実装にも影響してくる。View、Model、Controllerが全て同じフレームワークの方が開発スピードは早いが、完全にViewは分離しようとすると、View、Model、Controller間のインタフェース設計が必要になり開発スピードは落ちてくる。例えば、Ruby on Railsなどを使っていると、View、Model、Controllerのインタフェースが統一されてくるので楽だが、View、Model、Controllerが別のフレームワークになってくると、ViewとControllerは、json形式などの汎用形式でやりとりが必要になってくるなどである。

MVCという用語の功罪

  • 「ModelとViewを分離させる」という常識を浸透させたこと
  • 知ってしまうと当たり前のように考えてしまうが、MVCを知らない人が最初からModelとViewを分離しようと考えることは難しい。ViewとModelが混ざったソフトウェアを作ってしまい、痛い目をみるという経験をしてたどり着く考え方である
  • Viewの部分(html)をデザイナーに依頼、Model部分をエンジニアが開発という分業が可能になった

罪というか、自分の無知もありますが。。。

  • MVC1とMVC2というのがごっちゃになってコミュニケーションされる傾向があり、モヤっとさせる場面がある
  • Javaなどで扱うデザインパターンは、"MVC=MVC1"ですし、Webアプリ入門などで取り上げられるのは"MVC=MVC2"という感じで同じ用語で違う意味で使われている

MVCの捉え方によって違ってくる!

MVCをどのように捉えるのかでえらく変わってくることが解ってきました。

捉え方1 サーバーサイドのみでMVCを考える

  1. (Browser)View -> |Network| -> (Routing)Controller -> (Buiness Logic)Model -> (HTML)View -> |Network| -> (Browser)View
  • Model: データ重複、ロジック重複を避けるために共通化する。共通化する単位としてビジネスロジックなど
  • Controller: ユーザー入力を受け付けて、それに合ったModelを起動する
    • Push型: 担当するViewにModelの情報をPushする。
    • Pull型: (-)ViewがModelからデータをPullする。ControllerはViewと密着する。
  • View: ControllerからのデータをもとにHTMLを出力する

捉え方2 クライアントサイト、サーバーサイド、それぞれでMVCを考える

  1. (Browser)View -> Controller -> (Application Logic)Model -> |Network| -> (Routing)Controller -> (Buiness Logic)Model -> (DataFormat)View -> |Network| -> (Application Logic)Model -> (Browser)View
クライアントサイド
  • Model: サーバーサイドのAPIを利用しながら、そのアプリケーションが扱う領域のデータと手続きを表現する。
  • View: ユーザーにModelの状態を反映したHTMLを出力する
  • Controller: ユーザーの入力を受け取って判断し、Modelを起動する
サーバーサイド
  • Model: ビジネスロジック、データベース処理など
  • View: json形式等、APIに適したDataFormatでクライアントに返す
  • Controller: クライアントのリクエストを受け付けてそれに合ったModelを起動する

まとめ

  • MVCにはMVC1とMVC2がある
  • MVC1では、Modelの変化を引き金として、Viewにその変化を通知する。
  • MVC2では、サーバー側からModelの状態変更を通知することはHTTPがステートレスなのでできない。したがって、Modelの状態変更は、Controllerを経由してViewへの通知するように修正された
  • MVCといったら、WebアプリではMVC2を指す
  • サーバーサイドとクライアントと分割してMVCを考えた方がしっくりくる。
    • 調査以前は、Viewはブラウザ、ModelとControllerはサーバーとして、サーバーサイドとクライアントサイドを統合して考えていたが、分割して考えた方がMVCをすっきりと受け入れられる気がした。
  • Viewはブラウザと捉えずにHTML, json, xmlなど最終的にクライアントに返すフォーマットという広い捉え方にしよう
    • そういう捉え方をすることで、API+ネイティブアプリという構成であっても、MVCで捉えることもできる
    • 「APIサーバーはMVCパターンだけど、ネイディブ側はDocument-Viewパターンだよ」とか