2017年 09月の投稿を表示しています

スモールリーダーシップという本を読んでいる

この記事は公開されてから1年以上経過しており、情報が古い可能性があります。

別にチームリーダーとかそういう立場ではないのだけれども、チームがうまく回っていない気がしていてなんだかなーと思ってたけれども、どうしたらいいのかわからん。というときに Amazon を眺めていたら見つけたこれ。

Amazon | スモール・リーダーシップ チームを育てながらゴールに導く「協調型」リーダー | 和智 右桂 通販

帯に書かれていたことに一目惚れして、購入キメた。

× カリスマ
× イノベーション
× 精神論

技術でチームを回そう

こんなリーダーたちにオススメ
・初めてリーダーになった人
・チームの売上や進捗をうまくコントロールできない人
・部下を育てたいと思っている人
・チーム内で意見が対立して悩んでいる人
・ PDCA 、進捗管理、問題解決などの具体的手法を知りたい人
・身の丈にあったリーダーシップを身につけたい人

まだ一章を読んだ程度でしかないが、うんうん分かる分かるぞ~~~、といったような、自分の手で言葉や体系立てが出来ていないが経験上そうなのだろう、と思うところが出てくる。過去にえらい人に言われてきたことや、えらい人がやっている部分と一致するところもあって。自分の中で色々繋がり、ちょっと楽しくなっている。

うまく引用できそうなところがわからないので、読んでのざっくりまとめにはなるが、こういうところ。

業務はおよそ知識の差がある。すると出来る人がやるに陥りやすく、知識・経験を積んだ人が突如としてヒーローになる。ヒーローが生まれてもチーム全体としての学び、経験にはならない

リーダーは手を動かさない、1人でうごかない。メンバーの新たな学びにつながり、チームを考える時間が増える

まずは 決められたこと=規律 を守り、自ら考え変えていく=自律 へ

チームとしての学びのために、暗黙知を形式知へしていく。そのためにリーダーが形にする手伝いをする。形式知が増えるとチームの見方も変わり、また暗黙知が増えていく。そうしてまた形式知へ。

ところでこういう記事って書いたことがなくて、どういうポイントを抑えればよいのかいまいちわからない。メモというか、気になったところまとめを書きながら読んではいるが、こうやって記事にするとき書きすぎると本を買わなくても良くね?となってしまうだろうし。とりあえずはこんな形で、読んで特に!!!!となった部分を引用 or まとめる程度でいこう。

それにしても、ちびっこのころはやたら本を読んでいたが、いつしか苦手になってしまったようで、読むスピードと理解がなかなか進まない身体になってしまった。読めば適応してくると思うので頑張ろう。
ちなみに、会社で本買ってええぞって予算があって、それを使わせてもらっている。ありがたし。

CentOS 6 系から CentOS 7 系にアップグレードしたかった

この記事は公開されてから1年以上経過しており、情報が古い可能性があります。

某所の CentOS サーバをいい加減に 7 系にしよう!と思い、アップグレード手順なんかを調べていたら結構大変そうなことになった記録。結論としてまだアップグレードは出来てない。大して yum 以外でモリモリ入れたのも無いし、およそ nginx と php が動けば良いだろうな、入れ直しが手っ取り早そうだ。

公式 Wiki にアップグレードツールの件が記載されている。
TipsAndTricks/CentOSUpgradeTool - CentOS Wiki

目につく部分に警告が書かれている。

DO NOT USE this tool. Warning: use of this tool is currently BROKEN as several system-critical packages are of a higher version number in CentOS 6.7 than they are in CentOS 7 so those do not get upgraded correctly. This renders yum and several other system tools non-functional.

要するに CentOS 6.7 以降のパッケージは CentOS 7 に入っているパッケージよりもバージョンが進んでいるものもあり、うまく動かないらしい。詰まる該当パッケージのバージョン下げれば良いんじゃないか、行けるっしょ、という気持ちでトライしてみる。
※良い子は真似しないでね!

// まずは現状の確認をする
# cat /etc/redhat-release
CentOS release 6.9 (Final)


// アップグレードツールのリポジトリを追加
# vi /etc/yum.repos.d/upg.repo

// 以下を記載

[upg]
name=CentOS-$releasever - Upgrade Tool
baseurl=http://dev.centos.org/centos/6/upg/x86_64/
gpgcheck=1
enabled=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6


// 必要なツールのインストール
# yum install redhat-upgrade-tool preupgrade-assistant-contents


// 可能なアップグレードを確認
# preupg --list
CentOS6_7


// アップグレード検証をする
# preupg -s CentOS6_7

Preupg tool doesn't do the actual upgrade.
Please ensure you have backed up your system and/or data in the event of a failed upgrade
 that would require a full re-install of the system from installation media.
Do you want to continue? y/n

// y を入力

Gathering logs used by preupgrade assistant:
All installed packages : 01/11 ...finished (time 00:01s)
All changed files      : 02/11 ...finished (time 04:51s)
Changed config files   : 03/11 ...finished (time 00:00s)
All users              : 04/11 ...finished (time 00:00s)
All groups             : 05/11 ...finished (time 00:00s)
Service statuses       : 06/11 ...finished (time 00:00s)
All installed files    : 07/11 ...finished (time 00:04s)
All local files        : 08/11 ...finished (time 00:40s)
All executable files   : 09/11 ...finished (time 00:07s)
RedHat signed packages : 10/11 ...finished (time 00:00s)
CentOS signed packages : 11/11 ...finished (time 00:00s)
Assessment of the system, running checks / SCE scripts:
001/096 ...done    (Configuration Files to Review)
002/096 ...done    (File Lists for Manual Migration)
003/096 ...done    (Bacula Backup Software)
004/096 ...done    (MySQL configuration)
005/096 ...done    (Migration of the MySQL data stack)
006/096 ...done    (Changes related to moving from MySQL to MariaDB)
007/096 ...done    (PostgreSQL upgrade content)
008/096 ...done    (GNOME Desktop Environment underwent several design modifications in CentOS 7 release)
009/096 ...done    (KDE Desktop Environment underwent several design modifications in CentOS 7 release)
010/096 ...done    (several graphic drivers not supported in CentOS 7)
011/096 ...done    (several input drivers not supported in CentOS 7)
012/096 ...done    (several kernel networking drivers not available in CentOS 7)
013/096 ...done    (several kernel storage drivers not available in CentOS 7)
014/096 ...done    (Names, Options and Output Format Changes in arptables)
015/096 ...done    (BIND9 running in a chroot environment check.)
016/096 ...done    (BIND9 configuration compatibility check)
017/096 ...done    (Move dhcpd/dhcprelay arguments from /etc/sysconfig/* to *.service files)
018/096 ...done    (DNSMASQ configuration compatibility check)
019/096 ...done    (Dovecot configuration compatibility check)
020/096 ...done    (Compatibility Between iptables and ip6tables)
021/096 ...done    (Net-SNMP check)
022/096 ...done    (Squid configuration compatibility check)
023/096 ...done    (Reusable Configuration Files)
024/096 ...done    (VCS repositories)
025/096 ...done    (Added and extended options for BIND9 configuration)
026/096 ...done    (Added options in DNSMASQ configuration)
027/096 ...done    (Packages not signed by CentOS)
028/096 ...done    (Obsoleted rpms)
029/096 ...done    (w3m not available in CentOS 7)
030/096 ...done    (report incompatibilities between CentOS 6 and 7 in qemu-guest-agent package)
031/096 ...done    (Removed options in coreutils binaries)
032/096 ...done    (Removed options in gawk binaries)
033/096 ...done    (Removed options in netstat binary)
034/096 ...done    (Removed options in quota tools)
035/096 ...done    (Removed rpms)
036/096 ...done    (Replaced rpms)
037/096 ...done    (GMP library incompatibilities)
038/096 ...done    (package downgrades)
039/096 ...done    (restore custom selinux configuration)
040/096 ...done    (General)
041/096 ...done    (samba shared directories selinux)
042/096 ...done    (CUPS Browsing/BrowsePoll configuration)
043/096 ...done    (CVS Package Split)
044/096 ...done    (FreeRADIUS Upgrade Verification)
045/096 ...done    (httpd configuration compatibility check)
046/096 ...done    (bind-dyndb-ldap)
047/096 ...done    (Identity Management Server compatibility check)
048/096 ...done    (IPA Server CA Verification)
049/096 ...done    (NTP configuration)
050/096 ...done    (Information on time-sync.target)
051/096 ...done    (OpenLDAP /etc/sysconfig and data compatibility)
052/096 ...done    (OpenSSH sshd_config migration content)
053/096 ...done    (OpenSSH sysconfig migration content)
054/096 ...done    (Configuration for quota_nld service)
055/096 ...done    (Disk quota netlink message daemon moved into quota-nld package)
056/096 ...done    (SSSD compatibility check)
057/096 ...done    (Luks encrypted partition)
058/096 ...done    (Clvmd and cmirrord daemon management.)
059/096 ...done    (State of LVM2 services.)
060/096 ...done    (device-mapper-multipath configuration compatibility check)
061/096 ...done    (Removal of scsi-target-utils)
062/096 ...done    (Configuration for warnquota tool)
063/096 ...done    (Disk quota tool warnquota moved into quota-warnquota package)
064/096 ...done    (Architecture Support)
065/096 ...done    (Binary rebuilds)
066/096 ...done    (Debuginfo packages)
067/096 ...done    (Cluster and High Availability)
068/096 ...done    (Quorum implementation)
069/096 ...done    (fix krb5kdc config file)
070/096 ...done    (File Systems, Partitions and Mounts Configuration Review)
071/096 ...done    (Read Only FHS directories)
072/096 ...done    (Sonamebumped libs)
073/096 ...done    (SonameKept Reusable Dynamic Libraries)
074/096 ...done    (Removed .so libs)
075/096 ...done    (In-place Upgrade Requirements for the /usr/ Directory)
076/096 ...done    (CA certificate bundles modified)
077/096 ...done    (Developer Tool Set packages)
078/096 ...done    (Hyper-V)
079/096 ...done    (Content for enabling and disabling services based on CentOS 6 system)
080/096 ...done    (Check for ethernet interface naming)
081/096 ...done    (User modification in /etc/rc.local and /etc/rc.d/rc.local)
082/096 ...done    (cgroups configuration compatibility check)
083/096 ...done    (Plugable authentication modules (PAM))
084/096 ...done    (Foreign Perl modules)
085/096 ...done    (Python 2.7.5)
086/096 ...done    (Ruby 2.0.0)
087/096 ...done    (SCL collections)
088/096 ...done    (System kickstart)
089/096 ...done    (YUM)
090/096 ...done    (Check for usage of dangerous range of UID/GIDs)
091/096 ...done    (Incorrect usage of reserved UID/GIDs)
092/096 ...done    (NIS ypbind config files back-up)
093/096 ...done    (NIS Makefile back-up)
094/096 ...done    (NIS server maps check)
095/096 ...done    (NIS server MAXUID and MAXGID limits check)
096/096 ...done    (NIS server config file back-up)
Assessment finished (time 06:32s)
I/O warning : failed to load external entity "/usr/share/openscap/xsl/security-guide.xsl"
compilation error: file /usr/share/preupgrade/xsl/preup.xsl line 40 element import
xsl:import : unable to load /usr/share/openscap/xsl/security-guide.xsl
I/O warning : failed to load external entity "/usr/share/openscap/xsl/oval-report.xsl"
compilation error: file /usr/share/preupgrade/xsl/preup.xsl line 41 element import
xsl:import : unable to load /usr/share/openscap/xsl/oval-report.xsl
I/O warning : failed to load external entity "/usr/share/openscap/xsl/sce-report.xsl"
compilation error: file /usr/share/preupgrade/xsl/preup.xsl line 42 element import
xsl:import : unable to load /usr/share/openscap/xsl/sce-report.xsl
OpenSCAP Error:: Could not parse XSLT file '/usr/share/preupgrade/xsl/preup.xsl' [oscapxml.c:416]
Unable to open file /root/preupgrade/result.html
Usage: preupg [options]

preupg: error: [Errno 2] No such file or directory: '/root/preupgrade/result.html'

やっぱりうごかない。調べると openscap のバージョンを下げることで先にすすめるらしい。
CentOS6.8 から CentOS7 へのアップグレード - demandosigno

// バージョン確認
# rpm -qa | grep openscap
openscap-1.2.13-2.el6.x86_64


// 古いものを入れる
# rpm -Uhv --oldpackage http://dev.centos.org/centos/6/upg/x86_64/Packages/openscap-1.0.8-1.0.1.el6.centos.x86_64.rpm
http://dev.centos.org/centos/6/upg/x86_64/Packages/openscap-1.0.8-1.0.1.el6.centos.x86_64.rpm を取得中
準備中...                ########################################### [100%]
   1:openscap               ########################################### [100%]


// 確認
# rpm -qa | grep openscap
openscap-1.0.8-1.0.1.el6.centos.x86_64


// 再度ツール実行
# preupg -s CentOS6_7

~~

Assessment finished (time 06:21s)

Result table with checks and their results for main contents:
---------------------------------------------------------------------------------------------------------------
|Bacula Backup Software                                                                    |notapplicable     |
|MySQL configuration                                                                       |notapplicable     |
|Migration of the MySQL data stack                                                         |notapplicable     |
|Changes related to moving from MySQL to MariaDB                                           |notapplicable     |
|PostgreSQL upgrade content                                                                |notapplicable     |
|GNOME Desktop Environment underwent several design modifications in CentOS 7 release      |notapplicable     |
|KDE Desktop Environment underwent several design modifications in CentOS 7 release        |notapplicable     |
|several graphic drivers not supported in CentOS 7                                         |notapplicable     |
|several input drivers not supported in CentOS 7                                           |notapplicable     |
|Names, Options and Output Format Changes in arptables                                     |notapplicable     |
|BIND9 running in a chroot environment check.                                              |notapplicable     |
|BIND9 configuration compatibility check                                                   |notapplicable     |
|Move dhcpd/dhcprelay arguments from /etc/sysconfig/* to *.service files                   |notapplicable     |
|DNSMASQ configuration compatibility check                                                 |notapplicable     |
|Dovecot configuration compatibility check                                                 |notapplicable     |
|Net-SNMP check                                                                            |notapplicable     |
|Squid configuration compatibility check                                                   |notapplicable     |
|Added and extended options for BIND9 configuration                                        |notapplicable     |
|Added options in DNSMASQ configuration                                                    |notapplicable     |
|w3m not available in CentOS 7                                                             |notapplicable     |
|report incompatibilities between CentOS 6 and 7 in qemu-guest-agent package               |notapplicable     |
|restore custom selinux configuration                                                      |notapplicable     |
|samba shared directories selinux                                                          |notapplicable     |
|CUPS Browsing/BrowsePoll configuration                                                    |notapplicable     |
|FreeRADIUS Upgrade Verification                                                           |notapplicable     |
|bind-dyndb-ldap                                                                           |notapplicable     |
|Identity Management Server compatibility check                                            |notapplicable     |
|IPA Server CA Verification                                                                |notapplicable     |
|OpenLDAP /etc/sysconfig and data compatibility                                            |notapplicable     |
|SSSD compatibility check                                                                  |notapplicable     |
|Clvmd and cmirrord daemon management.                                                     |notapplicable     |
|device-mapper-multipath configuration compatibility check                                 |notapplicable     |
|Removal of scsi-target-utils                                                              |notapplicable     |
|Quorum implementation                                                                     |notapplicable     |
|fix krb5kdc config file                                                                   |notapplicable     |
|cgroups configuration compatibility check                                                 |notapplicable     |
|System kickstart                                                                          |notapplicable     |
|NIS ypbind config files back-up                                                           |notapplicable     |
|NIS Makefile back-up                                                                      |notapplicable     |
|NIS server maps check                                                                     |notapplicable     |
|NIS server MAXUID and MAXGID limits check                                                 |notapplicable     |
|NIS server config file back-up                                                            |notapplicable     |
|several kernel networking drivers not available in CentOS 7                               |pass              |
|several kernel storage drivers not available in CentOS 7                                  |pass              |
|OpenSSH sshd_config migration content                                                     |pass              |
|Configuration for quota_nld service                                                       |pass              |
|Disk quota netlink message daemon moved into quota-nld package                            |pass              |
|Luks encrypted partition                                                                  |pass              |
|Configuration for warnquota tool                                                          |pass              |
|Architecture Support                                                                      |pass              |
|Debuginfo packages                                                                        |pass              |
|Cluster and High Availability                                                             |pass              |
|Read Only FHS directories                                                                 |pass              |
|In-place Upgrade Requirements for the /usr/ Directory                                     |pass              |
|Developer Tool Set packages                                                               |pass              |
|Hyper-V                                                                                   |pass              |
|Check for ethernet interface naming                                                       |pass              |
|Plugable authentication modules (PAM)                                                     |pass              |
|Ruby 2.0.0                                                                                |pass              |
|SCL collections                                                                           |pass              |
|Incorrect usage of reserved UID/GIDs                                                      |pass              |
|Compatibility Between iptables and ip6tables                                              |informational     |
|VCS repositories                                                                          |informational     |
|Removed options in coreutils binaries                                                     |informational     |
|Removed options in gawk binaries                                                          |informational     |
|Removed options in netstat binary                                                         |informational     |
|Removed options in quota tools                                                            |informational     |
|GMP library incompatibilities                                                             |informational     |
|CVS Package Split                                                                         |informational     |
|httpd configuration compatibility check                                                   |informational     |
|NTP configuration                                                                         |informational     |
|Information on time-sync.target                                                           |informational     |
|Disk quota tool warnquota moved into quota-warnquota package                              |informational     |
|File Systems, Partitions and Mounts Configuration Review                                  |informational     |
|Sonamebumped libs                                                                         |informational     |
|SonameKept Reusable Dynamic Libraries                                                     |informational     |
|Foreign Perl modules                                                                      |informational     |
|YUM                                                                                       |informational     |
|Reusable Configuration Files                                                              |fixed             |
|Replaced rpms                                                                             |fixed             |
|package downgrades                                                                        |fixed             |
|OpenSSH sysconfig migration content                                                       |fixed             |
|State of LVM2 services.                                                                   |fixed             |
|Configuration Files to Review                                                             |needs_inspection  |
|File Lists for Manual Migration                                                           |needs_inspection  |
|Obsoleted rpms                                                                            |needs_inspection  |
|Binary rebuilds                                                                           |needs_inspection  |
|CA certificate bundles modified                                                           |needs_inspection  |
|Python 2.7.5                                                                              |needs_inspection  |
|Check for usage of dangerous range of UID/GIDs                                            |needs_inspection  |
|Packages not signed by CentOS                                                             |needs_action      |
|Removed rpms                                                                              |needs_action      |
|General                                                                                   |needs_action      |
|Removed .so libs                                                                          |needs_action      |
|Content for enabling and disabling services based on CentOS 6 system                      |needs_action      |
|User modification in /etc/rc.local and /etc/rc.d/rc.local                                 |needs_action      |
---------------------------------------------------------------------------------------------------------------
Tarball with results is stored here /root/preupgrade-results/preupg_results-170926155342.tar.gz .
The latest assessment is stored in directory /root/preupgrade .
Summary information:
We found some potential in-place upgrade risks.
Read the file /root/preupgrade/result.html for more details.
Upload results to UI by command:
e.g. preupg -u http://127.0.0.1:8099/submit/ -r /root/preupgrade-results/preupg_results-*.tar.gz .

出てきた。結構いろいろみてくれるのね、しゅごい。

/root/preupgrade/result.html に詳細があるそうなので、ドキュメントルートに持っていって、ブラウザから確認すると次のような画面になった。

  • 半分くらいの項目はちゃんと確認しないと危ない気がする
  • がんばってアップグレードしてもとっちらかった状態になりそう
  • web サーバとして簡単に使っている程度なので、バックアップ全部とって入れ替えるもあり

というところから、入れ替えちゃったほうが早そうだなあ、という結論。

まずは docker だったりで CentOS 7 を準備して、稼働中のサービス、設定ファイルや鍵を移しつつ、いろいろ動作するか確認したのち、まるっと入れ替える、という流れになりそーう。

つづく。

Progressive Web Apps Roadshow Tokyo 2017 に参加した

この記事は公開されてから1年以上経過しており、情報が古い可能性があります。

PWA Roadshow Tokyo 2017 という PWA についていろいろ説明したり、コードを弄ったり、未来を感じたりするイベントに参加してきたログ的なもの。

イベント応募

Google Developers Japan のブログを見ていたら、たまたまイベントやるよ!を見かける。

Google Developers Japan: Progressive Web Apps Roadshow Tokyo 2017 を開催します

PWA という単語をぼちぼち聞いてはいて、てっきり Web サイトがアプリ化できる!というものだと思っていたものの、それ以上はまったくしらなかったので、せっかくだから勉強してみよう!と Google 主催のイベントに応募したのがきっかけ。

イベントページはここ。
Progressive Web Apps Roadshow Tokyo 2017 | ホーム

イベントページ自体は日本語なものの、セッションが英語だったりちょこちょこと文言が英語で若干不安になるが、それはまあそれとして、英語の勉強にもいいでしょう、と気合を入れて応募した。定員200名に入るのかどうかわからなかったが、後日参加できるよ!のメールが来てホッとしたことを覚えている。

受付~会場入り

平日だったので、ギョムをおやすみさせてもらっていった。 Google 東京オフィスはたぶん初めて…、前に何かのイベントでいったことあるかも?六本木ヒルズ、森タワーにそのオフィスを構える。

Google のオフィス | Google

東京
〒106-6126
東京都港区
六本木 6-10-1
六本木ヒルズ森タワー
電話: +81-3-6384-9000

日比谷線六本木駅からもそう遠くない。 1 番の出口を目指すと到着する。

通常、森タワーに部外者が入るには、対応する LL または UL にある受付の人に名刺を見せたりが必要だが、今回は多くの人が訪れることもあってか LL にイベント用の受付が設置されていた。受付の方にメールで来ていた参加証を見せる。参加者の名前をリストにしているようで、来た人欄に丸がつけられた。

会場は 27 階…(だったと思う)で C ホールからエレベーターで行く。

会場はプレゼンホールのようになっていて、足元に電源あり、 27? くらいのモニター 9 枚による巨大なスクリーン、後方席には上にもディスプレイ、そしてゆったりとした座席、さらには後ろに通訳ブース、とすごく整っていた会場だった。
窓、明かりは壁際のスイッチでオンオフできるよう。壁一面が真っ白でスクリーン周辺は黒なっていて、見やすかった。

話し声が聞こえたところによると、このスペースはわりかしできたばかりで、このイベントが初めての通訳ありだったり大規模にやったり、人柱てきなものになっていたそう。

ちなみに Google のゲスト用の無線 LAN アクセスポイントの SSID は GoogleGuest でパスワード無しだった。よく見ると GoogleGuestLegacy みたいなものもあって、無線 LAN ルータを刷新でもしたのかな?なんて思ってた。

いろいろセッションメモ

ずらーーーーっとして、見にくい点は申し訳ない。整えるとちょっとつらみが。。

キーノート: Progressive Web Apps: What, Why and How

  • Ajax で Web は変わった
    • Google Maps で革命が、ズーム、スクロール、自動読み込み
  • 2014年にモバイルとデスクトップの利用率が入れ替わる
    • モバイルでは 87% のユーザがアプリ体験を重視している、通知やホームスクリーン
    • ユーザの時間はよく使うアプリ 3 つにおおよそ集約する
      • 新規インストールもなかなか起こらない
    • モバイルにおいて)アプリは体験、可能性、将来性が高い一方で多くにリーチすることは難しい
    • モバイルにおいて)Web は逆にリーチできるが体験がアプリほど高くない
      • PWA でそれを解決していきたい
  • PWA はユーザエクスペリエンス向上のため、エンドユーザのための仕事をすること
  • PWA で新しいことを多数学ぶ必要はない
    • いままでのことを応用、よりよくするだけ
    • FIRE = Fast Integrated Reliable Engaging の観点で価値を生み出していく
      • Fast: 動作を軽快に、パフォーマンスを良く
      • Integrated: ネイティブアプリと同じような OS と融合したユーザ体験を
      • Reliable: 通信が途切れてもよいような Web 、信頼性を高く
      • Engaging: ユーザ体験、Web サイトの価値向上
    • こういったものに Service Worker が必要不可欠
      • ブラウザとサーバ、ネットワーク通信との間にはまり、オフライン機能の提供をすることもできる
  • PWA は Progressive(段階的) である
    • Web で作ったアプリケーションをデスクトップでもモバイルでも
    • モバイルは端末、環境がさまざまなので、フィーチャーディテクションを使い、段階的に機能・体験を提供しよう
  • PWA はどんどん広まっている
    • Twitter, LANCOME, Lyfy, Nikkei, Rakuten, suumo, travago, CNET, CNN, forbes, …

セッション1: Integrated Experiences

  • FIRE の 2つめ
    • web と OS がより連携し、よりよい体験を
  • 80% のユーザがモバイルのホーム画面上でアプリを移動している
    • 利便性や見た目を重視する
    • web ページのショートカットをホーム画面に置くことはいままでもできていた
      • 設置するにあたってメニュー操作が必要、ブラウザが立ち上がる、オフラインで見れないといったエクスペリエンスの問題があった
    • WebApp Manifest で解決する
      • ウェブアプリ マニフェスト  |  Web  |  Google Developers
      • 見た目上はほぼアプリになり、どんなアイコンか、起動画面をどうするかを設定できる
      • ブラウザによって実装がことなるが、自動でサジェストしてくれる
        • Chrome の場合は次の通り
          • WebApp Manifest が正しく書かれている
            • アプリ名、144px のアイコン、 URL
            • 要するにアプリっぽく見えるためのプロパティが必須
          • Offline Support with Service Worker
            • ネットワークがなくても動作する、という信頼がないとだめ
          • Engaged User
            • スパムアプリでないことを Chrome がチェックしている
            • 基準は明確に決まっておらず、様子を見ながらころころ変わっている
              • 「たまたまアクセスがあったときにサジェストを出す」ではない
          • こうしたややこしいことがあるのは FIRE を約束するため
  • Web Payments
    • モバイルの CVR は デスクトップ比で 66% 低い
      • 購買には支払情報、届け先などをフォーム上で入力が必要
      • モバイルで入力するのは面倒なので、離脱率が高いように見える
    • そのフォームが面倒なことに対して Autofill がすでにある
      • 最適なフォームの作成  |  Web  |  Google Developers
      • ブラウザはフィールドの属性値と並びで判断している
        • zipcode は国際的なのでわかるが yubin は判断できない
      • うまく動かないケース多いハズなので、正しく autocomplete 属性を設定すること
        • 新しい属性を入れるので元々のコードを汚すことがない
    • すべての Web サイトに対して、お金を払うことについて一貫したユーザ体験を提供することが Web Payments の目的
      • 支払い方法、配送先を決められる
        • Android Pay など支払い専用アプリケーションを利用することもできる
          • 複数指定して、対応している支払いするものだけ表示される
        • 指定された生情報が JS に渡される
      • お金を支払う処理まで行うものではなく、決済と配送先の入力を簡易的にするためのもの
      • クロスブラウザ、クロスプラットフォーム、オープンなエコシステム
    • Autofill は古いブラウザでも問題がないので積極的に利用していくとよい
      • フィーチャーディテクションを行い Web Payments も利用していくとユーザ体験が向上する
    • Web Payments はまだまだ発展する余地があるので、デベロッパーからの意見を取り入れていきたい
  • 他にも OS と融合していく機能・体験はある
    • Media Session, Media Capture, Casting Support, …
    • PWA として他のアプリと同じように振る舞うための API

セッション 2: Reliable Experiences

  • Web だから、ネットワークがどうであれ、アプリのように振る舞うことでユーザビリティを上げる
    • アプリはオフラインでも動く
    • 地下鉄では移動して接続が切れたりする、勝手が悪い
    • 新高校では電波が立っているが通信がうまくできなかったりする
    • 世界では 60% のユーザが 2G 回線を利用して、 3 秒待つと 53% が離脱している
  • Service Worker で解決していく
    • ローカルプロキシとして動作する、データのキャッシュを行える
    • 常に動いているわけではなく、必要なときに動作する
      • ブラウザが閉じていても通知を受信したらワーカーが起動する、など
      • App like lifecycle
        • 登録、インストールが必要
        • ユーザは何が起こっているのか知る必要は無く、裏で静かに動く
    • ローカルプロキシとしては 2 回目の読み込みから動くようになる
      • 初回の読み込みは登録とインストールだけ
      • 2 回目以降でワーカ0のアップデートを確認し、動いていく
    • キャッシュやリクエスト、ネットワーク状況をコントロールできる
      • キャッシュ戦略をいくつか紹介
        • キャッシュを見て、なければネットワークへレスポンス
          • 更新ができないので、あまり変わらないようなものにオススメ
        • ネットワークを見て、なければキャッシュを見る
          • ネットワークが繋がりにくいと待たされるが、キャッシュ更新は可能
        • キャッシュとネットワークの同時リクエスト
          • キャッシュがあれば利用
          • ネットワークが来たらキャッシュ更新し、データ反映
        • キャッシュ→ネットワーク→キャッシュ
          • ネットワークが繋がらないので何かコンテンツを提供することができる
          • ユーザの離脱を回避する可能性がある
      • キャッシュはアプリケーションの性質によってベストな方法が変わる
  • Service Worker のためのツールセット
    • DevTools は有効に使える
      • 困ったときは Clear Storage を実行するとおおよそ解決する
    • workbox
      • Welcome to Workbox
      • キャッシュ戦略のコードを簡単に記述することができる

セッション 3: Engaging Experiences

  • Material Design が PWA でも活用できる
  • プッシュ通知
    • タイムリーに正確で意味のある必要な情報を通知することがよい通知
      • x) 飛行機の離陸時間が変わりました!
      • o) 登場予定の xx 便の離陸時間が 13:00 から 14:00 に変更になりました
    • PWA におけるプッシュ通知では Web Push プロトコルを利用する
      • まずクライアントサイドで、ユーザの許可、サブスクライブ、サーバ送信
      • サーバサイドで Web Push プロトコルを利用してメッセージ送信
        • プッシュサービスがメッセージ配信を行い、中身を見ることはできない
      • クライアントの Service Worker によってイベントが発行され、メッセージ処理を行うことができる
      • メッセージはパブリックキーとプライベートキーを使って暗号化される
    • ユーザ許可を得る際に、二重の仕組みにすると許可されやすい
      • 設定画面やアプリケーションのダイアログとして “許可する” を表示
        • その後にブラウザ側の許可を出す
      • さらに通知される情報を設定できるとよい
    • Service Worker のイベントが発行した時、適切なアイコンやボタン、画像などを設置するとよい
      • アクションへの設定もできるので、ユーザ体験を考えて実施していく

セッション 4: Secure Experiences

  • HTTPS は Identity, Confidentiality, Integrity のため
    • サイトは誰なのか保証する
    • クライアント / サーバ の機密性
    • 改ざん防止
  • しかし導入にあたって Unimportant, Perf, Cost, Maintenance の問題がある

セッション 5: Tooling - Lighthouse and Beyond

  • Chrome DevTools を開いたときの Audit というタブが Lighthouse と呼ばれている
  • 例として React を使った SPA を PWA 対応をしていってみる
    • Lighthouse を実行した結果をベースラインとして、施策をしていき点数の上下を見ていく
    • 実行した際にチェックリストがでるので、これにしがたって順番に対応をしていくとよい
    • iOS や Safari の対応のために、サーバサイドレンダリングを行う
      • Lighthouse でもそれによってパフォーマンス、モバイル対応の評価が向上する
    • PWA に向けてキャッシュをする際、App Shell + Dynamic Content という考え方を組むとよい
      • App Shell モデル  |  Web  |  Google Developers
      • アプリケーションのガワ、全体感を作る部分が App Shell で、これをキャッシュする
      • ネットワークが有効なら、コンテンツを更新していく
        • 更新したコンテンツをキャッシュするとファーストビューが素早く見れる
    • WebApp Manifest を入れることで “ホーム画面に追加” ができるようになるが、これは DevTools で確認できる
      • DevTools 内にリンクがあり、これを推すと “ホームに追加” サジェストを出すことができる
  • このようにして PWA 対応を進めていくとよい

コードラボ

  • コードラボに必要なソース、説明などはここからいける
  • この時間は、ここまで話を見て、聞いて、学んできたことを各自で自由にお試しください、という時間
    • せっかく作っている人たちがいるので、相談・議論したりするのが推奨されている
      • 通訳さんもいるのでドシドシ聞いていこう!
    • とにかく自由な時間
  • 聞こえた話
    • PWA に SPA は仕様としても個人的には必須ではない
      • SPA は敷居が高い
      • SPA にせずともリソースをキャッシュすればスピードアップすることは十分に可能
    • Cache Storage が更新されないバグがある
      • 6-12 週間くらいで FIX されていく動きあり
    • 1 サイトに複数の Service Worker がいることも可能
      • ただし管理上の危険が伴う、ワーカーを分ける必要はないのでは?
  • 作業メモ
    • まずは “はじめてのプログレッシブウェブアプリ” をやってみる
    • 時間があれば、ごみばこいんのトップページを PWA 対応してみたい
      • gomiba.co.in ではなく、ローカル環境で、ちょっとやってみる程度
    • importScripts という関数はワーカー内で利用できるグローバルなもの
    • そもそも Service Worker は Web Worker のうちの 1 つ
    • リセットするときは Clear Storage + タブを閉じる + タブを再度開く ことが大事そう
      • Service Worker のコードがいつアップグレードされるのかわかっていない感
    • コードラボの資料の手順が丁寧なのでそれを見るとよい
      • とりあえずやってみたい!というひとはググって “やってみたったwwww” みたいな記事は見なくていい
      • ただしいきなり色々な単語がでてきて、そこへの説明はあまりないので、辞書を 1 つずつ倒していく
    • ごみばこいんの PWA 対応に取り掛かる
      • workbox をオススメしていたので、これを使ってみる
        • とりあえずビルドなしでも利用はできるが CLI ツールとしての利用になるので Node.js は必要
        • workbox.prod.js が読み込めれば利用できるので、そのソースだけ持ってくればよい
          • CDN は無さそう? → Q&A
        • 外部リソース、CDN のキャッシュはできない?
          • workbox に生成してもらったコードは静的ファイルのみのキャッシュ
          • そのコードをそのまま使う分には CDN のキャッシュはできない
      • PWA 対応がちゃんと動くか確認するのに実機を使うようにするとちょっと面倒
        • USB つないで実機の Service Worker をリセットしたりする必要がある
        • デスクトップでも “ホームに追加” 的な動きはあるので、これを試して良ければ実機確認が良さそう
          • デスクトップにショートカットが置かれる
      • アプリっぽい見た目になるまではサクっとできる
        • Webview を埋め込む、いわゆるガワネイティブみたいなものは PWA 対応をすることで不要になりそう
        • ただし未経験がゆえにぼちぼちとハマるところはあるので、コレで実際に動かしているプロダクトに入れるのは慎重にやりたい

実際にできたものがこれ。

WebApp Manifest を入れ、 Service Worker によるオフラインサポートをしたら、ホームに追加が出来るようになり、ごみばこいんのトップページをアプリのように表示することができた。アイコンを適当に引き伸ばしたら白い余白が出来てしまったが…。

セッション 6: AMP

  • PWA における早くしよう!はキャッシュをして 2 回目から早くしよう!
    • AMP はそもそも最初から早くしよう!
  • モバイルの平均読み込み時間は 19 秒。 77% が 10 秒以上かかっている
    • 初回読み込みリクエストが 214 もある
    • 半分は広告
    • 早くしようとすると UX がよいが マネタイズが難しい
  • AMP のモチベーション
    • 遅い読み込み、スクロールできない、読み込みにおけるレイアウト崩れを解消する
  • AMP HTML + AMP JS + AMP Cache
    • AMP HTML
      • 広告はサポートしているアドネットのみ、認められないものは設置できない
      • 画像などのリソースなども指定された方法のみ有効
    • AMP JS
      • 遅延読み込みやサイズ指定を自動、または制約によって行う
    • AMP Cache
      • 正しく AMP 対応されていればクローラがやってきてキャッシュする
      • CDN 的なもので、各地にエッジサーバがあり、通信路も最適化される
        • エッジサーバはクローズではあるが、 Web の世界中で最適な対応になるまで時間かかるので、先に作った
        • 元ページはどうであれエッジサーバは HTTP/2 で通信できる
  • AMP + PWA
    • amp-install-serviceworker を利用すると Service Worker の登録ができる
    • AMP から遷移先のページをキャッシュすることができるので、常に早い Web 体験をすることができる
    • 大きく 3 つの方法が取れる
      • AMP as PWA
        • AMP そのものを PWA で扱う
        • AMP ページで Service Worker を登録し、遷移先に必要な AppShell をキャッシュする
        • 例) Learn AMP by Example
      • AMP to PWA
        • AMP から PWA にうまく遷移する
        • 動的なサイトなら有効、ただし手間がかかる
      • AMP in PWA
        • PWA に AMP を埋め込む
          • AMP HTML を持っておく
          • AMP ページにはそれをそのまま出す
          • PWA ページにはコンテンツとして埋め込む
        • iframe では遅いので Shadow DOM で解決する必要がある

クロージング

  • PWA が伝わったと思う
    • プログレッシブエンハンスメントなので、段階的に、できるところから、ユーザエクスペリエンスのために対応していこう
  • 紹介できなかったところで、面白いものがまだまだある
    • Credential Management API
    • Web VR
    • Web Assembly
    • Silent Push

Q&A

  • Q) 新フローに対して慣れが必要だけどチェックアウトのフロー簡略化も対象か
    • Payment Request API の中で住所や支払い情報を入れる
      • 今まで複数のページに渡ってやっていたのがまとまる
    • サイトによって色々なパターンがあるので、一概にどうこうする、とはいえない
      • 個別に相談・提案します
  • Q) “ホーム画面に追加” を追加モジュールでできるか
    • 今後でやっていきたい
    • 議論としては右往左往しているような状況
  • Q) PWA は何を指しているのか
    • 答えはマーケティング用語であり、バズワード
    • 優れたユーザ体験を高速でエンゲージメントがあって…。これがPWAだ!というものはない
      • Lighthouse がチェックする指標が一番近い
  • Q) 通知の登録、削除、登録のフローは可能か
    • パーミッションを外した場合、ask、になっているなら許可を求める。
      • ブロックなら終了。何もできない
    • PWA.locks にはよいリスティングはある、誰でも登録できるが微妙なものもある
  • Q) モバイルのペイメント CVR の数字はどこのもの?
    • 社内の調査 PDF
    • ドイツ銀行の有料のもの
  • Q) CVR はフォームが悪いか、Web 体験が悪いか
    • フォームの途中でドロップすることが多いようにミメル
  • Q) Server Push はキャッシュ関係なく送るか?
    • その通り
    • Service Worker からはどうするか知ることはない
      • クッキーを使ってどういうキャッシュを持っているか確認する、という対策はできる
    • いい案があればコミュニティに挙げてみて
  • Q) Push 通知の許可に 2 度目のチャンスはない。ホームに追加も同じ?
    • 14 日後まででない。無視ではなくしない、にした場合 3 ヶ月後まででない
    • PWA コア機能を作ってるチームが UX やユーザリサーチをしているので変わる可能性はある
  • Q) PWA はアンインストールがあるか、キャッシュは誰が度のタイミングで責任を持つか
    • Android 、他のアプリと同じようにアンインストールすればクリアする、ストレージのクリアも同じ
    • ユーザとしてはサービスワーカーを処理するのはむずかしい
    • clear-site-data というヘッダーがあって、シグナルも増えている
    • quota を使って容量制限を設ける、ということも可能
  • Q) Service Woker スクリプトを CDN に置けるか?
    • できるが、やらないほうがいい
    • 重要なコンポーネントになるので、常に最新のバージョンを見れるようにしたほうがいい
      • ServiceWorker自体がキャッシュされるとこまっちゃう
    • CDN の必要性が薄まる
      • 必要なときにサーバにアクセスする。クライアントにキャッシュできる
  • Q) CDN のキャッシュはできるか?
    • クロスオリジンはキャッシュできる、がうまくいかないかも
    • Service Worker から fetch してキャッシュすることはできるが inspect できない
  • Q) Payment Request API でポイントから一部支払うことはできるか
    • マイナスを入れることでできる
    • UI の調整は今後も考えてない、声が多ければ仕様に増える可能性がある
  • Q) Service Worker がキャッシュするとリクエストは出るか?
    • リクエストが出る
    • AMP by Example を見てみるとよい
  • Q) 広告に対して行っているサポート
    • 遅延ロードがあるくらいで特にない
    • AMP フォーマットで広告を書くと、広告が AMP になるので CVR 問題は少ないはず
    • PWA については普通のページになるので特にない
    • Web だからユーザがオンラインで振る舞うので問題ない
      • オフラインならネイティブアプリの真似をすればいい
  • Q) しばらく Web to App の流れだったが App to Webが来るか?
    • Web とネイティブが近づいている。相互に機能が出入りして融合しつつある
    • ニュース、プッシュ通知が有効なので新規なら PWA でいいのでは?いまのアプリが順調ならアプリでもいい
      • PWA だからうまくいく!というわけではない、ユーザリサーチしていこう
  • Q) PWA に向いているライブラリ
    • 普通の Web なので、自由に、使いやすいものを選ぶとおい
  • Q) mBasS などあるが Push 通知をどうするか
    • 何かを推奨するわけでなく、標準のプロトコルを使うとよい
  • Q) ブラウザキャッシュと Service Worker キャッシュの違い
    • Service Worker キャッシュは明示的に今ここに欲しい、ができる
    • ブラウザキャッシュは来たらキャッシュするよ、という程度
  • Q) push 通知許可ダイアログ表示について、intervention でブロックするなどは検討してる?
    • (話を聞いてなくてメモできなかった。。。)
  • Q) クライアントに PWA を提案する一言キーワード
    • ベストなエクスペリエンスを提供します
    • ユーザを考えるべき
    • ネイティブアプリみたいな Web
    • それがベストなマーケティング
  • Q) PWA の分析は GA で可能か
    • はい、ガイドもあるので参考にしてね
    • workbox の中に analytics もあるので、オフライン中の動作をトラックして次にオンラインのときに送れる
  • Q) PWA のネイティブの今後。ネイティブ不要?
    • 常両方必要、どちらがいてよい、ということはない
    • Google でも仲良くやっている
    • よい体験のためにどちらの利点も考えていくべき
  • Q) ネイティブアプリと比べたバッテリー消費
    • とくにない
    • ネットワークアクティビティをあまり行わないようにしたほうがバッテリーが落ち着く
      • Service Worker でキャッシュするとリクエストがへってよい
    • 動画など GPU アクセラレーションをするなどなるとネイティブがつよい
  • Q) Service Worker v2 の中で面白いものは?
    • バックグラウンドシンク
      • オフライン中に起こったアクションをオンラインになったら送出できる
    • サイレントプッシュ
    • ストリーム
  • Q) Service Worker はアプリ開発者向け?ライブラリにオフライン機能を追加するようなユースケースは考えられているか?
    • ライブラリが持っているサービスワーカーのコードとマージする必要がある
    • 基本的には 1 つのサイトに 1 つのサービスワーカー
      • インポートや複数走らせるが議論されている
      • そのあたりのベストプラクティスが特にない、よいエコシステム成熟してない
  • Q) iOS は使えない機能があると思うが PWA でどうしたらよいか
    • まずよいエクスペリエンスをデスクトップ・モバイルで作って、よりよくしていくだけ
      • iOS だからやらない、とかっていう話ではない
    • フィーチャーがサポートされたときに有効になっていく
      • プログレッシブエンハンスメントしていく
  • Q) 他のベンダーとの連携アイオニックとか
    • Polymer でも一緒にやっていてので一緒に進めている
    • ブラウザベンダとも Chrome サミットでパネルディスカッションやセッションを進めている
      • Google だけでなく全体で進めている

そのほかの情報とか

参加者に関しては、ゲーム系会社の方がいたり、 SEO や広告を取り扱うメディア系の方がいたり、エンジニアだったり Web 担当者だったり、いやもう PWA やってて~な人もいたようだった。何ができてどう活かしていけるのか、 アプリと PWA 、 AMP と PWA 、これからの Web 、興味関心が高いように思えた。

今回のイベントのスライドはここにある。(ルートが Google Developer Groups になっているので公開してよいものだろう)

Twitter のまとめはここ

ほかの参加したよ!ブログはここ(リストの更新予定はない)

おわりに

今回のイベントを通して PWA について深まったが、 Google の人たちは終始、 Progressive Enhancement だ、と言っていたのが印象的だった。 PWA それ自体は別に Web をアプリ化するような技術そのものもでもなく、プッシュ通知を送れるような技術でもない。複数の Web Standard な API を組み合わせ、モバイルにおけるユーザ体験をより良くしていこう、というものだと認識した。

コードラボの時間で Push 通知や Payment Request API も試してみたかったが、時間が足りなかったのでそのうちやってみたい。デファクトスタンダードみたいなものがない、 W3C で通った API をやることになるだろうので、実プロダクトに入れづらいところだが、そこはプログレッシブにやれたらいいな。

無料で、ランチもついて、きれいな会場で、丸一日めっちゃ楽しかった。 Google さんありがとうございました!

Node.js から Headless Chrome を操作できる puppeteer を試す

この記事は公開されてから1年以上経過しており、情報が古い可能性があります。

いい感じに Javascript がゴリゴリ書かれていて、認証が必要なサイトを定期的にキャプチャを取る、という謎タスクが生まれ、ちょうど最近話題の Headless Chrome でも試してみるかな~~と思ったら puppeteer なるものがあるそうなので、これを使ってみる。

GoogleChrome/puppeteer: Headless Chrome Node API

GoogleChrome 配下にいるので Chrome 公式のパッケージだ。

何も気にせず動かしてみる

// puppeteer 導入
$ npm init
$ npm install puppeteer

ドキュメントにもあるサンプルソースを入れてみる。

// index.js
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await page.screenshot({path: 'example.png'});

  await browser.close();
})();

https://example.com へとアクセスし、そのページをキャプチャして ./example.png に保存するソースだ。 await で簡単わかりやすい書き方になるのが素晴らしい。これを動かしてみる。

$ node index.js
(node:30285) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Failed to launch chrome!
/var/www/html/crawl/bitbucket_billing/node_modules/puppeteer/.local-chromium/linux-497674/chrome-linux/chrome: error while loading shared libraries: libXss.so.1: cannot open shared object file: No such file or directory


TROUBLESHOOTING: https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md

(node:30285) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

かなしみ…。どうにも libXss.so.1 が開けずにエラーっぽい。パッケージを探してインストールし、再度動かしてみる。

$ yum provides */libXss.so.1
...

libXScrnSaver-1.2.2-6.1.el7.i686 : X.Org X11 libXss runtime library
Repo        : base
Matched from:
Filename    : /usr/lib/libXss.so.1

libXScrnSaver-1.2.2-6.1.el7.x86_64 : X.Org X11 libXss runtime library
Repo        : base
Matched from:
Filename    : /usr/lib64/libXss.so.1


$ sudo yum install libXScrnSaver
...

$ node index.js
(node:1345) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Failed to launch chrome!
/var/www/html/crawl/bitbucket_billing/node_modules/puppeteer/.local-chromium/linux-497674/chrome-linux/chrome: error while loading shared libraries: libgtk-3.so.0: cannot open shared object file: No such file or directory


TROUBLESHOOTING: https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md

(node:1345) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

GTK+3 が要求される。都合によって CentOS6 なのだが GTK+3 は入れるのがめっちゃ困難だった記憶。とりあえず GTK+3 というか Chrome を入れる方法を調べたら必要なライブラリも揃うだろう、と判断して調べる。

Google Chrome 60 Released - Install on RHEL/CentOS 7/6 and Fedora 26-20

Yes, they’ve discontinued support for RHEL 6.X version as of Google Chrome and on other side, latest Firefox and Opera browsers run successfully on the same platforms.

CentOS6 では Chrome は動かない、ダメ。Richard Lloyd 氏がスクリプトを作っているそうだが、そのサイトでも、いつまでも古いものを使うな、って書いてあった。

Site has been shut down

You have two choices really (ignoring Chromium, which no-one seems to be keeping up-to-date for RHEL/CentOS 6):

1. Use Mozilla Firefox ESR via "yum install firefox" that is shipped with RHEL/CentOS 6. Unfortunately, this can be up to a year out of date w.r.t. features compared to the more "normal" Mozilla Firefox that you can download from Mozilla (but that "normal" Mozilla Firefox is now also using GTK+3 and doesn't work on RHEL/CentOS 6 either).

2. Move to RHEL/CentOS 7, perhaps first in a VM before upgrading on bare metal once the VM is to your satisfaction. The latest Google Chrome installs and runs out-of-the-box on RHEL/CentOS 7 (see below).

気を新たにdockerで動かす

まあ、一旦使ってみるなら docker でもいいか。

$ docker run -it -d -v $(pwd):/var/www/puppeteer_test centos:latest
Unable to find image 'centos:latest' locally
latest: Pulling from centos
6c5159923047: Pull complete
acec82331181: Pull complete
1c1b67b33c28: Pull complete
Digest: sha256:57c91a43765de2147fa666a128477bc6101d6fda660feaaa5fbb1a8b110c934f
Status: Downloaded newer image for centos:latest
2be8ec65e6e4db3d852d563b82cc4c90ca90f62b4aaa6304d6e00f06d6a4a9e7

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
2be8ec65e6e4        centos:latest       "/bin/bash"         16 seconds ago      Up 16 seconds                           romantic_sinoussi

$ docker exec -it 2be /bin/bash

# cd /var/www/puppeteer_test/
# ls
index.js  node_modules  package-lock.json  package.json

# node -v
bash: node: command not found

// nodeがいないので入れる
# curl -sL https://rpm.nodesource.com/setup_8.x | bash -
# yum install nodejs

# node index.js
(node:114) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Failed to launch chrome!
/var/www/puppeteer_test/node_modules/puppeteer/.local-chromium/linux-497674/chrome-linux/chrome: error while loading shared libraries: libpangocairo-1.0.so.0: cannot open shared object file: No such file or directory


TROUBLESHOOTING: https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md

(node:114) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

// とりあえず yum provides で探しながら一個ずつ入れていく
// をまとめたものがこちら
# yum groupinstall "Development Tools"
# yum install pango libXScrnSaver libXcomposite libXcursor libXi libXtst cups-libs libXrandr GConf GConf2 alsa-lib atk gtk3

// 起動してみる
# node index.js
(node:11985) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Failed to launch chrome!
[0920/101508.987383:ERROR:zygote_host_impl_linux.cc(88)] Running as root without --no-sandbox is not supported. See https://crbug.com/638180.


TROUBLESHOOTING: https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md

(node:11985) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

root で --no-sandbox なしは認められないらしいのでソースを変える。

// index.js
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({args: ['--no-sandbox']});
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await page.screenshot({path: 'example.png'});

  await browser.close();
})();

再び実行。

# node index.js

# ls
example.png  index.js  node_modules  package-lock.json  package.json

キャプチャ取れたので、画像を確認。

勝ち。

というわけで puppeteer 動いた。CentOS6 で CentOS7 が動いてて~ってちょっとアレなので、バージョン上げてまた試……、じゃない、本来の目的だった認証通してキャプチャできるかをやらなくちゃ。続く。

Rx と Promise と。

この記事は公開されてから1年以上経過しており、情報が古い可能性があります。

Rx 云々を見かけるたびに Web でそんな出番ないような…?非同期やすとりーむや配列的なのをよろしくするやつ?と、もはや知ることを放棄していて。今頃もったいないなーと思ったので、改めてちょっと調べるの巻。

Rx について

ReactiveX - Intro

オブザーバーパターンを拡張したもので、シーケンスなデータやイベントをサポートするため、スレッドやノンブロックIOとかを抽象化して組み立てることができる。オブザーバーパターン = 監視する人と通知する人がいるよー、というイメージでとりあえずはよい。

Promise について

JavaScript Promiseの本

非同期処理を上手くパターン化して書くための、統一的なインターフェース。ここではオブザーバーという話はない。 コードを見ても、非同期を取りまわすためのいい感じのインターフェースである、というイメージ(個人の感想です)

Rx とPromise はどう使い分けるとよさそう?

いくつかサイトを眺めてみて。

JavaScriptの非同期処理には何を使うべきか - Qiita
State, Promise & Reactive プログラミング
What are the differences between observables and promises in JavaScript? - Stack Overflow

で、 Stackoverflow の回答が結構それっぽいのかなあと。

Simply put: A promise resolves to a single value asynchronously, an observable resolves to (or emits) multiple values asynchronously (over time).

ざっくり訳すと。

Observable (= Rx として) は多数の非同期を継続的に処理したい
Promise は単発の非同期処理をしたい

なので。

Rx は配列操作とか、画面操作とか、とかと相性がよい
Promise は単発になりがちのもの、外部呼出し(Ajaxとか)と相性がよい

このボタンおしたら Ajax して、待機状態にして、結果が来たらここを書き換えて、イベント設定して、… なんてものは Rx と Promise を組み合わせるといいのかもしれない。が、昨今のフロントエンドにおいては Flux なんかでライブラリの中でよろしくやっていることが多いので、あえて開発する人が関与していくことは少ない…?

どちらかというとアプリ系で Rx が盛り上がってる気がしていて、 Web フロントではそうでもないような…。どっちも知識薄くてわからんのだけど、言語が違っても画面とロジック、裏でデータがほいほい、みたいなことってどちらも一緒のことだと思うんだけど、その差はなんなんなん?

docker を使っていてポートを指定するときに IP アドレスを指定できる

この記事は公開されてから1年以上経過しており、情報が古い可能性があります。

開発用だったり検証用だったりで docker をぼちぼち使っているのですが、ゲストのポートをホストのポートへバインドするときに、IPアドレスを指定できます。

$ docker run -it -d -p 127.0.0.1:10080:80 myapp

どこで使うんだよって話ですが、セキュリティを考えるときには使うんじゃないっすかね、たぶん。

IPアドレスの指定がないと 0.0.0.0 で待ち受けるので、接続をどこからでも受け付けます。そのため、例えばホスト側で nginx 等を使って何かしらの認証が必要なリバースプロキシをしていたとしても、指定ポートでコンテナに直接アクセスができてしまいます。

nginx で不特定多数から見られないよう Basic 認証を設定していたのですが、見れるのかな?ってポート指定してアクセスしたら無事に見れてしまって、うふふってなってました。

$ docker run -it -d -p 10080:80 nginx
485e21a84ea180bc69db198bcdb7e417fb61d2747642059b8bd4435873aa1503

$ netstat -nao | grep 10080
tcp        0      0 :::10080                    :::*                        LISTEN      off (0.00/0/0)

$ docker rm -f 485
485

$ docker run -it -d -p 127.0.0.1:10080:80 nginx
94ea5a9d74578fc69777cf0dc3b7dc918ce2e4ec74fef52441521a8d163680d8

$ netstat -nao | grep 10080
tcp        0      0 127.0.0.1:10080             0.0.0.0:*                   LISTEN      off (0.00/0/0)

ドキュメントはここ
https://docs.docker.com/engine/reference/commandline/run/#publish-or-expose-port--p-expose

いまさらになるけど”結婚式したよ”というご報告 追記(2017/12/20)

この記事は公開されてから1年以上経過しており、情報が古い可能性があります。

プロポーズはおととしの 12 月にしていて、入籍は昨年 4 月にしていて、お金や時間の都合で時間差、今年の 5 月くらいに結婚式を挙げてました。

あ、結婚式の日に結婚式なう~~~みたいなツイートしそこねた…。

当然ながら人生初の結婚式だったわけですが、いわゆるホテルウェディングとか、神社でーとか、そういう形にはしませんでした。

株式会社 CRAZY がやっている、コンセプトや内容、演出などなど、1 からウェディングのプランニングしていって、最高の1日をみんなで作っていこう、というものを利用しました。クレイジーって最近テレビ出たりメディア出たりで結構盛り上がっているそうですよ☆

株式会社 CRAZY (株式会社クレイジー) | CRAZY,Inc.

コンセプトウェディングのプロデュースチーム | CRAZY WEDDING (クレイジーウェディング)

そんなクレイジーウェディングで迎えた、ぼくらの最高の1日の様子をちょっとだけご紹介。

余談ですけど Theta S + 自撮り棒 をもっていったので、ハットなのも相まってステッキ!?って驚かれました。集合写真とか、歩き回るときに動画とったりして面白い画になりましたとさ。おすすめ。

よかったこと

・これやるならウン万ですよみたいな営業がほぼされなかった
・現実的に出来ることは何でもできる(お金しだい)
・コンセプトをちゃんとすり合わせて決めるので本人たちの納得感、やった感が非常に強い
・家族メッセージしっかり伝えられた

自分たちがどういうことをしたいのかを考えたり、自分たちがどういう人生を歩んできたのかを話したり、そもそもなんで結婚式するんだっけを考えたり…。そうこうして、プロデューサーの方からワクワクするようなコンセプトが提案されました。
一部抜粋ではありますが、ぼくらの場合はこんなコンセプトです。


オモシロ屋
いつでもどこでも オモシロイこと 創ります 材料はこの世界にあるものすべて

新しいものを ゼロから創り出すことを 楽しんで生きてきた 僕と
誰よりユニークを愛し 好奇心を元に 手を抜かず生きてきた 私

ふたりでいたら最強です

こうしたい!という想像力と 遊びゴコロがあれば どんなものだって創り出せる
飽くなき探求心と 人を笑顔にしたい想い それがオモシロ屋の原動力


最初にこのコンセプトを見聞きしたときにちょっと感動しちゃって涙が出かかるほどに。で、このコンセプトを、結婚式当日直前の会場装飾と初対面ってときにも読まれて、会場ながめてこれまだ涙が。エモい言葉に弱いんですかね、ぼく。

コンセプトイメージがレトロなモダンな和風チックな感じで、それに合わせて会場の装飾だったり、席札だったり、ぼくらの衣装も見ていました。だから、その日、その会場はすべてが「オモシロ屋」です。っていうくらい作りこむ文字通りのクレイジーな集団で、こっちはめっちゃ驚くし感動するしでした。

微妙だったところ

・プロデューサーさんめちゃんこいそがしそう

ほぼすべて良くて、はーーーーやってよかったなーーーー、みたいな空気感に包まれていたのですが、プロデューサーさんが掛け持ちしたりで、結果忙しそう(に見える)ので、連絡するのに気が引けてしまったり、とかとか。
話を聞くところによると、それで提供したいことや考えたいことがうまくできていなかったところもあったそうなので、体制ややり方を変えていっているそうですよ!これからやるひとはきっと大丈夫だと思います!

個人的な反省

・炎上プロジェクトだった(直前でもうれつにがんばらないといけなかった)
・人呼びたりなかった。。 Party !!にしたかったけど会場キャパとかコンテンツとか。。

二人で作っていくので、細かいスケジュールややること整理は自分たちで管理していかないといけないです。もちろんプロデューサーさんがお手伝いはしてくれますが、すでに書いてある"忙しそう"が相まって、煽りがされないこともしばしばありました。
一応 Trello を使ってやることと日程の管理はしていたのですが、直前 1-2 週間くらいは動画つくったりなんだりーってやっていました。
あ!ぼくらの場合は、ある程度自分たちでも作りたいっていう意思があったので、動画とか。プロにお任せするのがお手軽らくちんではあるのですが、自分たちでやったほうがやりたいようにできるんじゃないかなーと。

ちなみに動画作成は Vegas Pro 14 です。2,3 年くらいまえに 5000 円?だったかなあ、のセールをしてたところで買って、それからずっと使ってます。動画作成する仕事ではないのですが、ちょこちょこと動画つくってよ~~なんてお願いがあったりするので、そういうところで。

個人的にはめっちゃ人呼んでパーリナイにして高まる曲をもりもりと流したかったのですが、予算都合だったり、妻との調整の結果、ってところでですね。それでももう少し呼びたい人たちもいましたし、呼べなかったのマジゴメンの気持ち。会場キャパが 80 くらいだったんだよ~~~

結婚式に向けてやったことざっくりまとめ

そういえばこんなことをやってよかったよ~とか共有しておこうと思っていて忘れてたのでここに追記する(2017/12/20)

タスク管理

やることだったり、期限が付いたものだったりなど、基本的に Trello で主に管理していた。

Trello

写真を集める

昔の現像された写真を集める時にはフォトスキャンが便利ちゃんだった。
集めた写真は Google フォトに挙げて、人物タグやアルバム機能が最高にいい。Googleフォトマジすごくて、ちびっこ写真とかは他人扱いされるんだけど、マージが出来て、自分のタグにどんどん写真が入ってくる。

フォトスキャン by Google フォト - Google Play の Android アプリ
フォト - Google フォト

出席欠席、招待どこまで送るの管理

Googleスプレッドシートを使った。思いつく限り人をわーーーと出して、どこまで入れようか決めていった。

Google スプレッドシート - オンラインでスプレッドシートを作成、編集できる無料サービス

ちなみに出欠だけじゃなくて、何をいくつ発注していくらだよ、みたいな管理も別シートでしていた。1個のスプレッドシートになっていたことが追えてよかった。

web 招待状

ぼくらは紙の招待状を作っていなくて、ぼくらの色を出そうとwebにした。 .wedding なドメインとって、サイトからフォームから全部作ったわ。とりあえずキャプチャだけ。

技術的にはこんなところ。

フロントエンド:Twitter Bootstrap3 をベースに FLOCSS に従って独自の定義を加えた
サーバサイド:PHP, Slim を使っていい感じに制御
ミドルウェア:nginx + Apache, Let's Encrypt で SSL

引き出物選び

東急ハンズのカタログギフトにした。カタログギフトって楽しいよね、しかも東急ハンズだよ、東急ハンズ。気持ち的なところで人によって金額が違う。
引き菓子は住んでいた場所の近所のコーヒー屋さんとケーキ屋さんのものにした。あとふにゃん。
プチギフト?出るとき配るお菓子はイクミママのどうぶつドーナツ。しろくまとねこ。イクミママめっちゃかわいいのでオススメ。

東急ハンズのカタログギフト from hand to hand
ふにゃん(サラダ味) | おいしい時間
イクミママのどうぶつドーナツ

動画コンテンツの作成

既にかいたとおりなんだけど、 Vegas Pro 14 を使っている。セールしてたときに 5,000 円くらい。そろそろ Vegas Pro 15 がセールしてるかも。
知人に頼まれたりでポチポチ触ってたりもしたんだけど、結婚式だっていうから相当気合入れて、コンテをざっくり作ったり、動画構成を練って、妻とすりあわせて、作っていった。時間はまあそりゃかかるよねってところだけど、意外と簡単にできるので、時間に余裕があれば自分で作るのが嫌でなければやってみてもいいと思う。
ニコモンズやYoutubeで動画素材やエフェクト素材がたくさんあるのでそういうのも使った。あとはVegasでこうやればできる!みたいなチュートリアル動画もめっちゃ見た。

「VEGAS Pro 15」 プロ用映像制作ソフトの最新版|ソースネクスト
トップページ - ニコニ・コモンズ

当日の写真撮影

ぼくが欲しいというのもあって Theta S でも撮ろうぜ!ってやった。結論からいくと Theta S の勝手がイマイチわからないまま使ったのでうまく撮れなかった。

製品紹介 | RICOH THETA

想定ではこういう写真を取りたかった。多分ゲスト側…?半分スタッフくらいで、あちこち動きながら使うと最高なんだろうな、って知見を得たので、今度知人の二次会とかで使っていこうと思う。

どの写真も必ず「全員」の笑顔が写る。結婚式を最高の思い出にするカメラとは | TABI LABO

ちなみに動画も撮っていたんだけど開始20分くらいでバッテリー切れたこともかなしい。その後も撮影はちょっとだけ出来たは出来た。特に調査なしにやったのは大失敗だった、もう取り戻せない。

積極的に有給を使っていく

結婚式準備なんですよ~~^^とかって有給、あるいは半休をよく使えた。そういうのできる会社っていいよね。たすかる。


というところで。

結婚式も披露宴も、こちらは非常に楽しくやっていましたし、ゲストの盛り上がりも良くて、後で話を聞いてもよかったねー、だったのも嬉しいポイントでした。自由度高くお金と頑張り次第でなんでもいけるのでクレイジーウェディングおすすめです!

あと干し芋を置いておきますね、お祝いの気持ちが湧いてきたらお願いします。
http://amzn.asia/j4BudTt

NGINX Unit なるものリリースされたらしいのでとりあえず PHP でも動かしてみる

この記事は公開されてから1年以上経過しており、情報が古い可能性があります。

NGINX Unit なるものがリリースされたらしい。

・NGINX 公式サイトの情報
NGINX Unit

・NGINX Unit 公式サイト
NGINX Unit

・見かけた記事
NGINXからアプリケーションサーバ「NGINX Unit」がオープンソースで登場。PHP、Go、Pythonに対応。Java、Node.jsにも対応予定 - Publickey

ドキュメントに書かれているインストール方法や設定を見てたらパッと出来そうだったので思いたってやったったの巻。

どうにも公式サイトのドキュメンテーションを見ると CentOS と Ubuntu 向けにはパッケージが適当されているっぽい。なのでコレを利用する。また nginx が既にいる環境でやると便利そうなので docker で立ち上げていく

// ホストにて
$ docker run --name nginx-unit -d -p 8080:80 nginx
$ docker exec -it nginx-unit bash

// 以降はコンテナ内、ゲストで作業

// 準備
# apt-get update
# apt-get install curl net-tools vim less

// キーの登録
# curl http://nginx.org/keys/nginx_signing.key > /tmp/nginx_signing.key
# apt-key add /tmp/nginx_signing.key

// /etc/apt/sources.list に追記
# vim /etc/apt/sources.list
deb http://nginx.org/packages/mainline/ubuntu/ xenial nginx
deb-src http://nginx.org/packages/mainline/ubuntu/ xenial nginx

// nginx-unit のインストール
# apt-get update
# apt-get install unit


// コンフィグ確認
# cat /etc/init.d/unit
CONFIG=/etc/unit/config

// /var/run/control.unit.sock が設定用のソケットファイルっぽい
    dumpconfig)
        curl -sS --unix-socket /var/run/control.unit.sock localhost >${CONFIG}.new



# vim /etc/unit/config
{
     "listeners": {
         "*:8300": {
             "application": "myapp"
         }
     },
     "applications": {
         "myapp": {
              "type": "php",
              "workers": 3,
              "root": "/var/www/html/",
              "index": "index.php"
         }
     }
}

// 起動
# service unitd start

// コンフィグの確認
# curl --unix-socket /var/run/control.unit.sock http://localhost/
{
        "listeners": {},
        "applications": {}
}

// コンフィグの変更してみる
# service unitd stop
# mv /etc/unit/config /etc/unit/myconfig.json
# service unitd start

# curl -X PUT -d @/etc/unit/myconfig.json --unix-socket /var/run/control.unit.sock http://localhost/
curl: (52) Empty reply from server

# curl --unix-socket /var/run/control.unit.sock http://localhost/

// レスポンスが返ってこない

// ログ確認
# less /var/log/unitd.log

// ... とくにエラーっぽいものなし。

パッケージのものだとうまく動かない???

ということでソースから入れる路線を試す。

// パッケージからのものを消す
# apt-get remove unit

// 準備
# apt-get install git build-essential php php-dev libphp-embed
# cd /tmp
# git clone https://github.com/nginx/unit
# cd unit

// ビルド
# ./configure --prefix=/usr/share/unit/
# ./configure php
# make all

// インストール
# make install
# ln -s /usr/share/unit/sbin/unitd /sbin/unitd

// 起動
# unitd

// 設定してみる
# vim /tmp/unit_config.json

{
     "listeners": {
         "*:8300": {
             "application": "myapp"
         }
     },
     "applications": {
         "myapp": {
              "type": "php",
              "workers": 3,
              "root": "/var/www/html/",
              "index": "index.php"
         }
     }
}


# curl -X PUT -d @/tmp/unit_config.json --unix-socket /usr/share/unit/control.unit.sock http://localhost/
{
        "success": "Reconfiguration done."
}

# curl --unix-socket /usr/share/unit/control.unit.sock http://localhost/
{
        "listeners": {
                "*:8300": {
                        "application": "myapp"
                }
        },

        "applications": {
                "myapp": {
                        "type": "php",
                        "workers": 3,
                        "root": "/var/www/html/",
                        "index": "index.php"
                }
        }
}

// 動作確認
# echo "<?php echo 'hello php';" > /var/www/html/index.php
# curl localhost:8300
hello php

// nginx からプロキシしてみる
# vim /etc/nginx/conf.d/default.conf

upstream unit_backend {
    server 127.0.0.1:8300;
}

server {
    listen       80;
    server_name  localhost;

    location / {
        root   /var/www/html;
        index  index.html index.htm;
    }

    location ~ \.php$ {
        proxy_pass http://unit_backend;
        proxy_set_header Host $host;
    }
}

// 動作確認
# service nginx reload
Reloading nginx: nginx.

# curl localhost/index.php
hello php

出来ているようなので、もう少しちゃんと PHP を動かしてみる。

// phpモジュール追加
# apt-get install php-mbstring php-zip

// composer 導入
# curl https://getcomposer.org/installer > installer
# php installer
# rm installer
# chmod +x composer.phar

// Laravelプロジェクトインストール
# ./composer.phar create-project laravel/laravel app

// Laravel プロジェクトの色々設定
# chmod -R 777 /var/www/html/app/storage/
# php artisan key:generate

// nginx-uniti のルートディレクトリを変更
#  curl -X PUT -d '"/var/www/html/app/public/"' --unix-socket /usr/share/unit/control.unit.sock http://localhost/applications/myapp/root
{
        "success": "Reconfiguration done."
}

// 確認
# curl --unix-socket /usr/share/unit/control.unit.sock http://localhost/
{
        "listeners": {
                "*:8300": {
                        "application": "myapp"
                }
        },

        "applications": {
                "myapp": {
                        "type": "php",
                        "workers": 3,
                        "root": "/var/www/html/app/public/",
                        "index": "index.php"
                }
        }
}


// nginx のルートディレクトリを変更
# vim /etc/nginx/conf.d/defualt.conf

    location ~ / {
        proxy_pass http://unit_backend;
        proxy_set_header Host $host;
    }

# service nginx reload


// 動作確認
# curl localhost

// 何か出ていそうなのでブラウザで開く…!

イエーイ! NGINX Unit で Laravel アプリケーションが動いたぞ~~~空っぽだけど…。

ご覧とおり php-fpm は動いてなくて unit のワーカーが動いてるだけですねー、しゅごい。

# ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0  32648  3464 ?        Ss   00:50   0:00 nginx: master process nginx -g daemon off;
root         8  0.0  0.0  18224  2176 ?        Ss+  00:51   0:00 bash
root     26019  0.0  0.0  22196   852 ?        Ss   03:00   0:00 unit: main [unitd]
nobody   26021  0.0  0.0  32440   736 ?        S    03:00   0:00 unit: controller
nobody   26022  0.0  0.0 204620  1440 ?        Sl   03:00   0:00 unit: router
nobody   27293  0.0  0.7 269004 28232 ?        S    03:28   0:00 unit: "myapp" application
nginx    27330  0.0  0.0  33088  2152 ?        S    03:31   0:00 nginx: worker process
root     27331  1.2  0.0  18140  2064 ?        Ss   03:41   0:00 bash
root     27337  0.0  0.0  36572  1588 ?        R+   03:41   0:00 ps aux

現状では Go / PHP / Python に対応しているようで言語環境の準備と configure 時に言語指定すれば使えるようです。

手元にいい感じにお試せるアプリケーションがいないので細かい挙動の様子をみるなど出来ていないのですが、リリースニュース直後からはてぶが盛り上がったり github も盛り上がりを見せている(ように見える)ので、ちょっとしたバグなどなどあってももりもり直されていくんじゃないかなーという予感です。

そのうち Apache + mod_php / nginx + php-fpm / nginx + unit などでパフォーマンスも比べていきたいですねー!

Python で階層型クラスタリング

この記事は公開されてから1年以上経過しており、情報が古い可能性があります。

最近は Python をちょこまかといじることが増えてきたように感じています。というところで、クラスタリングのことを調べていたのですが、なんとなく k-means しておけばいいっしょ、くらいだったのですが、もっと奥深い色々が出てきて、クラスタリングわからないマンになりつつあります。そんなわけで、階層型クラスタリングを調べて、やってみたのでまとめておきます。

 

クラスタリングとは

クラスタリングとはデータを良い具合にまとめるという、教師なし学習の典型例です。何かしらの特徴量に沿って、データの流れや雰囲気をアルゴリズム的に見抜き、その様子でデータをまとめることができます。

クラスタリングとしてもっとも一般的なものは k-means でしょうか。k-means は非階層型クラスタリングと呼ばれています。具体的には以下のようなアルゴリズムでクラスタリングを行います。

  1. 事前に設定されるクラスタ数 K を元に、ランダム(※)にクラスタの中心を決定する
  2. 各要素から一番近いクラスタの位置を探し、それを各要素のクラスタとして設定する
  3. 各クラスタの重心を計算し、その重心位置をクラスタの中心として設定する
  4. 各要素から一番近いクラスタの位置を探し、それを各要素のクラスタとして設定する
  5. 各クラスタの重心を計算し、その重心位置をクラスタの中心として設定する
  6. ...これを重心の移動がしきい値を下回るまで、あるいは指定の回数を超えるまで実施する
  7. 最終的に、各要素から一番近いクラスタの位置が、その要素のクラスタとして決定される

(イメージ図@雑)

※ランダムにするか、程よい位置にするか(k-means++)などの初期位置決定の方法があります

後述する階層型との比較でも挙げますが、初期位置によってある程度クラスタの別れ方が分岐することも往々にして発生します。また、クラスタリング結果が毎回異なる可能性もあり、厳密な分類がほしい、なんとなく纏めるでは嫌、といった場合の要望をかなえることはできません。かといって階層型クラスタリングがこの要望を常に叶えられるわけでもないのですが...

今回取り上げる階層型との比較として後述しますが k-means では、事前にクラスタ数を設定する必要があるため、それが難しいような状況では大きな力を発揮することが難しいです。

ちなみにアルゴリズムとして x-means という、クラスタ数を自動で設定できるものもあります。K=2 として再帰的に k-means を実施し BIC と呼ばれるベイズ情報量規準が、設定したしきい値を下回るまで実行していくようなものになっています。詳しいことはぼくもあまりわからないので、その話が上がっている論文を見ると幸せになれると思います。

http://www.rd.dnc.ac.jp/~tunenori/xmeans.html

機械学習について触れていると、似たような「クラス分類」といったワードを見かけたこともあるかと思います。こちらはクラスタリングとは異なり、教師あり学習で「あるデータがどのクラスに属しているかを当てる」という全く別の問題になります。リンゴは果物、キャベツは野菜、というような、明確に正解があるようなデータを分類していくときには、クラス分類になります。

 

階層型クラスタリングとは

階層型クラスタリングは以下のようなアルゴリズムで処理されます。

  1. すべての要素に固有のクラスタを設定する
  2. クラスタを2つ取り上げていき、最も距離が近いもの(※)をくっつけて、新しいクラスタを作成する
  3. これを再帰的に実行し、最終的にクラスタが1つになるまで実施する

※「距離」の定義は設計次第です。ユークリッド距離、コサイン距離、など様々な計算方法があります。

※くっつけて出来上がったクラスタ間の距離計算は設計次第です。

  • クラスタが含む要素をそれぞれ比較し、最も近いものを距離とする(最近隣法)
  • クラスタが含む要素をそれぞれ比較し、最も遠いものを距離とする(最遠隣法)
  • クラスタが含む要素をそれぞれ比較し、平均的な距離とする(平均法)
  • クラスタが含む要素をそれぞれ比較し、それぞれの距離について分散を利用して程よい値を取る(ウォード法、よく使われているらしい)

(イメージ図@雑)

そうして出来上がったクラスタリング結果ですが、このままでは木構造のようになっており、データとして扱うにはどれがどういうクラスタに属しているのかを明確に決定しにくいです。実際にあるタスクで利用したときには、最大距離の7割を基準にして、クラスタを分割していました。状況によってはパラメータの調整する必要がありそうな予感がしています。

計算量と実際にかかる時間を考慮すると、既に説明した k-means や、この階層型クラスタリングが高速に処理でき、「それっぽい結果」が得られるので、解決したい問題にも寄ってくるとは思いますが、クラスタリングにおける選択肢として現実的なのかなあと思います。

 

階層型・非階層型(k-means)のそれぞれの使いどころ

階層型が活用できそうなところは以下のようなところではないでしょうか?

  • データセットのうち、それぞれの距離に何かしらの特徴がありそう
  • どれくらいのクラスタに分けたらいいかわからない

階層型の場合。クラスタ間の距離で並べ替えることも容易にできるはずなので、しきい値の設定が小さいせいでクラスタを分けすぎてしまっても、ある程度までは前後関係もそれっぽく追いついてきます。なので、出来上がった後に、人力でカバーすることも可能なのではないかなあと思います(それってどうなの感はありますが...)あるいはクラスタ数がいくつになるか想定できないような場合にも、全てのデータを一度まとめあげるので、自動で出てきた結果の様子を見つつ、手動でクラスタ分けしていくことができると思います。

一方で非階層型...もとい k-means の活用できそうなところは以下のようなところではないでしょうか?

  • データセットの雰囲気がわからないけど、いったん分割してみたい
  • 明確に K 個の分類をしたい

k-means では最初に K を決定しないといけないので、どうあがいても K 個のクラスタができあがります。この分ける数が重要になるような、クラス分類に近いようなものの場合であれば k-menas は非常に有効なのではないでしょうか。ただし、それぞれのクラスタ間で相関がないことや、中途半端な位置のデータはどちらとも言えないような結果になることは注意がいるかもしれません。

また、どんなデータを入れても、なんとなくまとめてくれるので、人力で確認したときも、「ああーこういう見方もあるのね、なるほど」という謎の納得感が得られやすいとも思います。

 

階層型クラスタリングを Python でやってみる

それでは Python で 階層型クラスタリングをやっていきます。ここでは sciki-learn に入っているアイリスデータセットを対象に pandas で読み込んで scipy.cluster.hierarchy を使っていきます。

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from scipy.cluster.hierarchy import linkage, dendrogram, fcluster
from sklearn.datasets import load_iris

# iris データセットの読み込み
iris = load_iris()
iris_df = pd.DataFrame(iris.data, columns=iris.feature_names)
iris_labels = list(map(lambda t: iris.target_names[t], iris.target))

# 階層型クラスタリングの実施
# ウォード法 x ユークリッド距離
linkage_result = linkage(iris_df, method='ward', metric='euclidean')

# クラスタ分けするしきい値を決める
threshold = 0.7 * np.max(linkage_result[:, 2])

# 階層型クラスタリングの可視化
plt.figure(num=None, figsize=(16, 9), dpi=200, facecolor='w', edgecolor='k')
dendrogram(linkage_result, labels=iris_labels, color_threshold=threshold)
plt.show()

# クラスタリング結果の値を取得
clustered = fcluster(linkage_result, threshold, criterion='distance')

# クラスタリング結果を比較
print(clustered)
print(iris.target)

出力結果

様子も見ずデータを絞ったりせず全てぶっこんで、というのはちょっと微妙なところですが setosa だけキレイに分かれましたね。setosa と、それ以外とで距離に開きがあるので、setosa だけ非常に特徴的ってことがわかります。それで versicolor と virginica はぼちぼち似ている、なんてところですね。

 

 

というわけで、階層型クラスタリングの話でした。

余談にはなりますが、そんなこんなで出来たやつをいい感じにクラスタ分けしたよ~^^って渡したら、分岐したやつを画像じゃなくて csv とかで欲しいって言われたのでそれはまた。

docker で MySQL を立ち上げたい。

この記事は公開されてから1年以上経過しており、情報が古い可能性があります。

タイトルそのまま。

// たぶん mysql 5.7 がプルされる
// が、わからんので DockerHub を要確認
$ docker pull mysql:latest

// mysqlコンテナの起動
//   オプションについて
//     -e    : 環境変数
//     --name: コンテナ名
//     -d    : バックグラウンド
//     -p    : ポートバインディング(ホスト:ゲスト)
//   環境変数について
//     MYSQL_DATABASE     : 作るデータべース
//     MYSQL_USER         : 作るユーザ
//     MYSQL_PASSWORD     : 作るユーザのパスワード
//     MYSQL_ROOT_PASSWORD: ルートパスワード
$ docker run --name my_mysql \
  -e MYSQL_DATABASE=homestead \
  -e MYSQL_USER=homestead \
  -e MYSQL_PASSWORD=secret \
  -e MYSQL_ROOT_PASSWORD=secret \
  -d \
  -p 13306:3306 \
  mysql

// 接続確認
//   -h : ホスト名
//   -P : ポート番号
//   -u : ユーザ名
//   -p : パスワードを入力するプロンプトを出す
$ mysql -h 127.0.0.1 -P 13306 -u root -p

記事書くときに Docker Hub を確認したら 5.7.19 が latest で指定されているっぽい。というか 8.0 系も指定できるのか、検証なんかにも便利そうだ。

library/mysql - Docker Hub

でもって docker で MySQL が立ち上がると、こうさ、ほら、ユニットテスト回すときなんかに、こうしてクリーンな DB を提供できてよさそうだなーって。
イメージとしてはこんな感じ。

{
    ...
    "scripts": {
        "test": "phpunit --verbose",
        "docker-test": [
            "composer docker-db-remove"
            "composer docker-db-create",
            "composer test",
            "composer docker-db-remove"
        ],
        "docker-db-create": "docker run --name test_mysql -e MYSQL_DATABASE=homestead -e MYSQL_USER=homestead -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=secret -d -p 13306:3306 mysql",
        "docker-db-remove": "docker rm --force test_mysql",
        "docker-db-connect": [
          "#  Copy this command!",
          "#  mysql --host=127.0.0.1 --port=13306 --user=homestead --password=secret homestead"
        ]
    },
    ...
}

composer docker-test とやったらコンテナが立ち上がり 127.0.0.1:13306 で待ち受けているので、そこを指定するように phpunit.xml だとか .env だとかで DB 接続用の値を設定すればよい。テストの後はコンテナがポイされるので、テスト用のDBはいつでもクリーンに。テストでコケても大丈夫なように、最初にコンテナをポイしたほうがいいのかな。

composer スクリプトで I/O を全部引き渡す方法がわからなかったので docker-db-connect タスクが非常にあやしい感じだけど、これくらいでもまあまあ運用していけるんじゃないかなーー

1 2