will and way

ただの自分用メモを人に伝える形式で書くことでわかりやすくまとめてるはずのブログ

Vagrant上でDockerコンテナプロビジョニングとDockerコンテナプロビジョニング環境のプロビジョニングにAnsibleを使う

タイトルが長い笑

この記事はQiita Advent Calendar 2015 23日目の記事です。 前日はunchemistさんのここがヘンだよAnsible (ハマりどころと対策について)でした。

qiita.com

Ansibleのカレンダーが空いてたので投稿いたしましたが、もしかしたらPackerとかDockerの割合が多いかもしれませんが、ご容赦くだされば幸いです!!

今回は、

  1. Vagrant上でPackerでDockerコンテナのプロビジョニング環境整備をプロビジョニングする際にAnsibleを使う
  2. 1で作った環境上で、さらにPackerでDockerコンテナをプロビジョニングするさいにAnsibleを使う

という2点を行ったメモを紹介します。

記事の対象者

  • Ansible, Docker, Packerを触りはじめたばかり

全体像

f:id:matsuokah:20151223130449p:plain

環境

Apps Version
Mac OSX 10.11
VirtualBox 5.0.10 r104061
Vagrant 1.8.0
Docker 1.7.1
Ansible 1.7.1
Packer 0.8.6

まず、MacOSX上では狭義の意味ではDockerは動かないですが Installation on Macの通りにすれば、ハイパーバイザー上にDockerをホスティング&フックするラッパーツールを使うことができます

しかし、自分の環境では、Packerでプロビジョニング中に進まないという現象に陥いったことや、Vagrant完結にしてホストを汚さないようにしたかったためVagrant上で構築しました。
また、Centos6系ではkernelが2.6ですが、Dockerを起動するには3系である必要があります。

Vagrant起動時にDockerコンテナプロビジョニング環境を整える

DockerコンテナプロビジョニングにはPackerを使うので、具体的にはCentosにDockerとPackerをインストールします。

AnsibleによるVagrantBoxのプロビジョニングポイント

VagrantfileにAnsibleでプロビジョニングする旨とplaybook.ymlを指定すればOK

あとは、playbookとrolesを拡充していくのみです。

サンプル

https://github.com/matsuokah/vagrant-docker-provisionergithub.com

git clone git@github.com:matsuokah/vagrant-docker-provisioner.gitしてディレクトリでvagrant upすればpackerが使えるイメージが立ち上がります。冪等性は担保してないのでご注意ください。

ファイルツリー

├── README.md
├── Vagrantfile
└── provisioning
    ├── playbook.yml
    └── roles
        ├── common
        │   └── tasks
        │       └── main.yml
        ├── docker
        │   ├── handlers
        │   │   └── main.yml
        │   └── tasks
        │       └── main.yml
        └── packer
            ├── files
            │   └── packer_0.8.6_linux_amd64.zip
            └── tasks
                └── main.yml

VagrantfileがあるディレクトリにAnsibleの設定を置いただけですね。

Vagrantfile

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config|
  config.vm.box = "centos7"
  config.vm.box_url = "https://github.com/holms/vagrant-centos7-box/releases/download/7.1.1503.001/CentOS-7.1.1503-x86_64-netboot.box"

  # provisioning
  config.vm.provision "ansible" do |ansible|
    ansible.playbook = "provisioning/playbook.yml"
    ansible.sudo = true
  end
end

Ansibleのモジュール実行の前提をしらずにハマる

Ansibleではモジュールを実行するためには、そのモジュールで使われるコマンドがインストールされているという前提を満たす必要があります。 例えばUnarcive moduleでは

Note
requires tar/unzip command on target host

のように、ホスト上でtar及び、unzipコマンドが使える必要があると言及しています。

TASK: [packer | Unarchive packer to installation directory] *******************  
failed: [default] => {"failed": true}  
msg: Failed to find handler to unarchive. Make sure the required command to extract the file is installed.

上記のようなエラーが出た場合、commonにはそれらの前提を整えるプロビジョニングを書くなどするといいかもです。これを知らないと、ただモジュールを実行しているだけなのに・・・とすこしハマリます。

PackerでDockerコンテナのプロビジョニングを行う

サンプル

https://github.com/matsuokah/packer-container-provisioner-samplegithub.com

後は、先程作ったpackerが実行可能なbox上で↑をcloneしてpacker build template.jsonとするだけです。

template.json

{
  "_comment": "Docker provisioner",
  "builders": [
    {
      "type": "docker",
      "image": "centos:7",
      "export_path": "/vagrant/image.tar"
    }
  ],
  "provisioners": [
    {
      "type": "shell",
      "inline": [
        "yum localinstall -y http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm",
        "yum install -y python-pip python-devel libstdc++ gcc gcc-c++ kernel-devel",
        "pip install ansible"
      ],
    },
    {
      "type": "ansible-local",
      "playbook_file": "ansible/playbook.yml",
      "role_paths": ["ansible/roles/common", "ansible/roles/nginx"],
      "staging_directory": "/tmp/docker-packer-provisioner"
    }
  ]
}

やっていることは、

  1. centosコンテナをpull
  2. Ansibleをインストール
  3. Ansible実行

例ではnginxをインストールしてみました。

/vagrant/image.tarとしてexportしたので

$ cat /vagrant/image.tar | docker import - centos_nginx:latest
$ docker run -d -i -t --name my_nginx centos_nginx:lagest "/bin/bash"

とでもすればnginxが起動できるかと思います。

動作確認するためにはVagrantfileでdockerへのポート転送のすればできるでしょう。

以上、「Vagrant上でDockerコンテナプロビジョニングとDockerコンテナプロビジョニング環境のプロビジョニングにAnsibleを使う」でした!!

リファレンス

Cocos2d-xにおけるOS依存機能利用のための実装

この記事はqiita advent calendar cocos2d-x 2015の22日目の記事です。 qiita.com

C++完結はできない

Cocos2d-xでは主にクロスプラットフォームな開発を期待して選ぶ方が多いと思います。

しかし、プラットフォーム依存な所、例えば文字の入力課金OS情報ユーザー情報へのアクセスをする場合にはそのプラットフォームで提供されているSDKを書く必要が出てきます。

また、Cocos2d-xで書くよりもOS依存のSDKの力を借りてネイティブで書いたほうがパフォーマンス向上に苦労しないケース(スクロールビューやGridView, CollectionViewなど)も少なくない上に、ユーザーにとっても使い慣れたUIを提供することができるというメリットもあります。

iOSの場合はObjective-CC++への互換があるため、Objective-C++として書けばほとんど苦労せずにプラットフォーム依存な部分にアクセス可能ですが、Androidの場合はJavaでAndroidSDKをつかって書く必要がありますね。

今回はこのAndroidSDKをC++からどう使うか?そして、開発を加速させるためにネイティブを使う側(C++)からJavaObjective-Cも同じインタフェースで呼べるようにするための設計をまとめていきます。

JNI

まずはC++からJavaを呼び出すにはJNIという知識が必要になります。一言で言えばJavaと他の言語をブリッジする機能です。

例と簡単な説明は以下に挙げますが、詳しい説明はOracleのJNIのリファレンスを読んでください。

Calc.java

package jp.matsuokah;

class Calc {
  public static int add(int x, int y)
  {
    return x + y;
  }
}

上記のaddC++から呼ぼうとするにはいくつかのステップが必要です。 一番簡単なパターンで説明します。

Cocos2d-xで用意されているJNI関連のユーティリティを使った場合

struct calc
{
  int add(int x, int y)
  {
    cocos2d::JniMethodInfo methodInfo;
    if (!cocos2d::JniHelper::getStaticMethodInfo(methodInfo, "jp/matsuokah/Calc", "add", "(I)I"))
    {
       throw std::runtime_error{"method couldn't found"};
    }
    auto result = methodInfo.env->CallStaticIntMethod(methodInfo.classID, methodInfo.methodID);
    methodInfo.env->DeleteLocalRef(methodInfo.classID);
    return result;
  }
}

順に流れを説明すると

  1. 文字列で定義したクラス名、メソッド名、メソッドのシグネチャを手がかりにstatic methodの情報を取得
  2. なければ例外を投げる
  3. メソッドをコールする
  4. JNI関連のオブジェクトを開放する
  5. 返却
  1. 文字列で定義したクラス名、メソッド名、メソッドのシグネチャを手がかりにstatic methodの情報を取得

これだけで、なんじゃこりゃ状態ですよね。
特にメソッドの情報を取得するところや、オブジェクトの開放は書くたびに頭を悩ませてくれそうです。

シグネチャが変わっても文字列なので、ランタイムでエラーになるまで気づかないかもしれません。

しかし、クラス名やメソッド名の検出はできないものの、シグネチャはテンプレート引数から自動生成、オブジェクトの開放はstd::unique_ptrを使えば意識しなくて済みそうです。

ということで、業務ではcocos2d-xのJniHelperを置き換えるライブラリを開発しました。(公開はできませんが擬似コードで方針を幾つか書きたいと思います)

今では例えば、WebViewを使う際には

void WebViewRef::load(const std::string& uri)
{
  auto env = get_env();
  jni::call_method<void>(env, this->ref_.get(), webview::load, uri);
}

上記はuriをロードする場合のメソッドです。リターン値、メソッド名、メソッドの引数を指定するだけで済むようになったのでJavaのメソッド追加やシグネチャの追加がとても楽になりました。

ブリッジ部は他のOSも絡むので以下にiOSAndroidを含めたクラススタックを載せ、概要を説明した後で、詳細を説明します。

iOS/Android共通WebViewの全体像

f:id:matsuokah:20151222224859p:plain

共通インタフェース

  • void* native_ptrとしてAndroidはRef、iOSはControllerのポインタをもつ
  • ネイティブから伝搬する各イベントハンドラをセットできるようにしている
  • 元の共通インタフェースのthisポインタをRef及びControllerに渡すことで、ネイティブからイベントハンドラを発火する

共通インタフェースの各翻訳単位の実装

  • void* native_ptrを各翻訳単位でキャストしてメソッドをコールする

Refクラス(Androidのみ)

AndroidのJNI関連のラッパークラス。JNIオブジェクトの確保/開放、メソッドやクラス情報の取得をテンプレート実装したもの

ネイティブ実装

  • 上位のレイヤからのメソッドを実行するコントローラであったり、Viewであったり。
  • 窓口となるクラスでは共通インタフェースの生ポインタをコンストラクタで受け取り、イベントハンドラを発火させる

Androidの場合の擬似コード

WebView.cpp

using ref_t = WebViewRef;

WebView::WebView() ptr_:{new WebViewRef{this}} {}
WebView::~WebView() {delete ptr_;}
void WebView::load(const std::string& url)
{
  static_cast<ref_t*>(this->ptr_)->load(url);
}

bool WebView::isLoading()
{
  return static_cast<ref_t*>(this->ptr_)->isLoading();
}

WebViewRef.hpp

#include ...

namespace android
{
class WebViewRef
{
  ref_wrapper ref_; // ref_wrapperはjavaオブジェクト用のカスタムデリータを定義したunique_ptrのエイリアス
  WebViewRef(const void* ptr);
  ~WebViewRef();
  void load(const std::string& uri);
  bool isLoading();
}
}

JNIEXPORT void JNICALL Java_jp_matsuoka_

WebViewRef.hpp

#include ...
namespace android
{

// シグネチャ関連
struct webview
{
  // qualified_nameはクラス名
  static constexpr auto qualified_name = "jp/matsuokah/Webview";
  // 以下メソッド名
  static constexpr auto load = "load";
  static constexpr auto isLoading = "isLoading";
  .
  .
  .
}

WebViewRef::WebViewRef(const void* ptr)
{
  auto env = get_env();
  this->ref_ = make_ref(env, make_object<webview>(env, reinterpret_cast<std::int64_t>(ptr)));
}

WebViewRef::~WebViewRef()
{
  this->ref_ = nullptr;
}

void WebViewRef::load(const std::string& uri)
{
  auto env = get_env();
  jni::call_method<void>(env, this->ref_.get(), webview::load, uri);
}

bool WebViewRef::isLoading()
{
  auto env = get_env();
  return jni::call_method<bool>(env, this->ref_.get(), webview::isLoading);
}

// 他のメソッドも同様に定義する
.
.
.

}

WebView.java

package jp.matsuokah;

import ...

class WebView {
  private long ptr;  
  private native void onLoad(long ptr);

  WebView(long ptr) {
     this.ptr = ptr;
  }

  void load(String uri) {
  } 

  boolean isLoading() {
    return true; //スタブ実装
  }
}

WebViewRef.cppではjni関連のライブラリをフル活用しており、実際にコールするところの実装は2行で済んでいます。

と、AndroidではこのようにネイティブとCocosの共通的なブリッジ部を開発しておりました。iOSC++の感覚で実装できるので紹介は省きます。

最後はほぼ擬似コードにはなってしまいましたが 共通インタフェースで各プラットフォームのAPIをコールできそうな雰囲気は感じ取っていただけたかと思います。

このようにフレームワークっぽくしておくと、追加実装になった時もそれに準じて書くだけで、ブリッジしていけるので個人的には開発効率化ができたなーと感じています。

書いていて気付きましたが、pimplパターンを使えば、共通インタフェースをもう少し上手く書けそうですね。

C++初心者ならビルドはBazelでラクしちゃいましょう

この記事は 初心者C++er Advent Calendar 2015, Qiita C++ Advent Calendar 2015 15 日目の記事です.

注意

  1. UbuntuもしくはMac OSXの環境が作れない方はそっと閉じてください。(VagrantUbuntuはすぐ準備できる)
  2. スマホアプリ畑の人間が書くので、それに向けた内容も多くなっています。
  3. PCからの閲覧をおすすめします。スマホで読むと、コードのレイアウトが崩れるようなので。

ビルドツールについて

みなさんはビルドオートメーションツールには何を使っていますか?

玄人界隈ではcmakeが定番です。

私が携わっているプロジェクトではgypと呼ばれるツールを使っています。
元々Chromiumで開発されていたGoogleオープンソースの一つで、node.jsにも使われているビルドツールです。

特殊なフォーマットに従ってファイルやマクロを定義することで、設定ファイルに応じたmakeファイルやXcodeなどプロジェクトを吐き出してくれる中間的なツールで、今は開発が進んでいないようです。

さて、前振りが長くなりましたが、このgypに取って代わる次世代ビルドツールとして開発されているのがBazelです。

BazelはCookpadの技術ブログでも取り上げてられているように、C++だけではなくスマホアプリや複数言語のビルドにも対応しているので、延長線上にポテンシャルがあるという観点も含めてBazelをピックアップしました。

また、話題の機械学習フレームワークTensorFlowもBazelでビルドされてます。

少しの設定ファイルを書けば機能単位でライブラリ化や依存関係を定義できるので、初心者はBazelでラクしましょう!!!

サンプル

github.com

↑を元に、解説していきます。

Hello World

インストール方法は環境によって違うのと、簡単なので割愛します。

HelloWorldプロジェクトのファイル構成

HelloWorld
├── Makefile
├── WORKSPACE
└── src
    ├── BUILD
    └── main.cpp

注目すべきはWORKSPACEBUILDです。

WORKSPACE

The location of the workspace directory is not significant, but it must contain a file called WORKSPACE in the top-level directory. The WORKSPACE file may be an empty file, or it may contain references to external dependencies required to build the outputs.

Getting Started with Bazelより引用

「WORKSPACEという名前のファイルがプロジェクトのトップとなるディレクトリに必要で、他のプロジェクトへの依存性を定義するもの。依存性がなければ空ファイルとしておいておけばOK」とのこと

今回は、外部のソースに依存しないのでWORKSPACEは空ファイルです。

TensorFlowWORKSPACEでは、外部に依存する設定が定義されていますね!

zipをダウンロードしてhashチェックしたり、gitのリポジトリをhash指定で持ってきてくれたりしてくれるので使い勝手が良さそうです!

BUILD

Bazel figures out what to build by looking for files named BUILD in your workspace

Getting Started with Bazelより引用

「BazelはBUILDと呼ばれるファイルからビルドすべきファイルを割り出す」とのこと。

つまり、WORKSPACEが外部のソースに対する依存関係の設定、BUILDが具体的なビルドの設定であり、両方ともビルドに欠かせない設定ファイルということになります。

それでは早速設定を見ていきましょう。

main.cpp
#include <iostream>

int main()
{
  std::cout << "Hello World" << std::endl;
  return 0;
}

まずは、ソースから。シンプルなHello Worldなので解説は不要ですね。

src/BUILD
cc_binary(
  name = "main",
  srcs = ["main.cpp"],
)

main.cppmainというターゲット名で実行ファイルを作成するという設定になります。nameのみがrequiredなパラメータです。

Makefile
all: run

BAZEL=$(shell which bazel)
.PHONY: run
run : build
    $(BAZEL) run //src:main

.PHONY: build
build : 
    $(BAZEL) build //src:main

.PHONY: clean
clean :
    $(BAZEL) clean

BazelはURIスキームライクにパッケージを定義しており、それらをdependencyとして扱うことができます。 そして、サブコマンドの後にパッケージを指定することでビルドターゲットとしてビルドを開始することができます。

Makefile内に定義してある//src:mainはsrcディレクトリ以下にあるBUILDファイルに定義されているmainというターゲット名を示していることになります。

実行してみる

make runを実行すればsrc/BUILDに定義されているmainがビルドターゲットとなり、main.cppコンパイルされ、mainターゲットが実行されます。

f:id:matsuokah:20151215010642g:plain

失敗させてみる

セミコロンを抜いてみました f:id:matsuokah:20151215010428g:plain

実行後のディレクト

HelloWorld
├── Makefile
├── WORKSPACE
├── bazel-HelloWorld
├── bazel-bin
├── bazel-genfiles
├── bazel-out
├── bazel-testlogs
└── src
    ├── BUILD
    └── main.cpp

このように、bazelというプレフィックスでビルド関連のディレクトリ郡が生成されます。自動生成されたディレクトリやファイルは、bazel cleanで一挙に削除することができます。

HelloWorldプロジェクトではMakefileエイリアスを定義したのでmake cleanで同様のことが可能です。

static libraryの依存関係を定義し、mainから呼び出してみる

HelloWorld出力部分をstatic library化し、//src:mainから依存関係を解決して、コールしてみます。

HelloWorldStaticLibのプロジェクト構成

.
├── Makefile
├── WORKSPACE
└── src
    ├── greeting
    │   ├── BUILD
    │   ├── hello.cpp
    │   └── hello.hpp
    ├── BUILD
    └── main.cpp

MakefileWORKSPACEは全く一緒です。

また、hello.hpp,hello.cpp,main.cppはHello Worldの出力を関数化しただけなので記載を割愛します。

src/greeting/BUILD

cc_library(
  name = "greeting",
  srcs = glob(["*.cpp"]),
  hdrs = glob(["*.hpp"]),
  visibility = ["//visibility:public"],
  linkstatic = 1,
)

あらたな設定が出てきましたが、雰囲気でおわかりかと思います。 まず、cc_libraryという単位に変わりました。

さらに、srcsがファイルの列挙ではなくglob関数を使っています。
お察しの通りワイルドカードコンパイルターゲットとなるファイルを指定しています。hdrsも同様です。

visibilityはそのビルド単位の可視性となります。適切に設定することでビルド単位間の結合性を疎にできるので、必要なcc_libaryだけをpublicにすることが好ましいです。 publicにしたことで、src:mainからsrc/greeting:greetingが可視化されています。

linkstaticはフラグです。

src/BUILD

cc_binary(
  name = "main",
  srcs = glob(["*.cpp"]),
  deps = ["//src/greeting"],
)

depsという設定が入りました。greetingライブラリに依存してるんですね〜。

実行してみる

実行結果は変わらないので割愛して、変わったところをば

~/p/h/HelloWorldStaticLib ❯❯❯ ls bazel-out/local_darwin-fastbuild/bin/src/greeting/
_objs         libgreeting.a

libgreeting.aができていますね!

と、こんな感じでstatic libraryやshared libraryをつくれて依存関係もよしなにしてくれるので、コーディングに時間を割きたい初心者C++erにはおすすめなのではないでしょうか。

gitignore

*.swp
*~
.DS_Store
bazel-*

特に問題なければ、bazel-*のようにワイルドカードでexcludeしちゃって問題無いでしょう。

Bazelはドキュメントもしっかりあるので、「最適化オプション使いたい!」だとか、「マクロを定義したい!」だとかあれば、参考にしてみてください。Bazelで良き、C++のビルドライフを〜!

よく通っているコーヒースタンド

遅くなってすみません。。。すっかり忘れておりました。

この記事は「コーヒー Advent Calendar 2015」5日目の記事です。

www.adventar.org

俺氏について

ブラックコーヒーデビューは小学4年生位の頃。

元々は牛乳入れないとダメだったのですが、コーヒー牛乳を飲み過ぎて、腹を壊しまくった結果、牛乳入れずに飲んだら苦いものの、腹を壊さない事に感動し、飲み続けていたら「あれ?うまい!?」とはまっていった次第であります。

最近は健康診断で貧血気味と診断されコーヒー飲み過ぎてることを怒られました。

いわゆる渋谷で働く〜系のエンジニアで、渋谷に近いところに住んでいます。 渋谷周辺って結構コーヒー激戦区だったりするんですよ!

早速、おすすめをリストアップしていきますっ!

THE COFFEE SHOP

渋谷駅からは歩いて10分くらい。本日のコーヒーは300円くらいでフレンチプレスで淹れてもらえます。初めてここで飲んだ時は感動しました。 コーヒーにこだわるきっかけとなったお店です。

おいてる豆はすべてスペシャルティコーヒーなので、どれも個性がはっきりしているので、好みの豆に出会ったらリピート間違いなしです!

店員さんも気さくに色々教えてくれるので待ってる間も無駄になりません!

About Life Coffee Brewers

オフィスの目の前にあるが故に週3,4くらいで通っているスタンド。ここもスペシャルティコーヒーのみ。 ペーパードリップを感じさせないドリップ技術。淹れ方や温度を聞いたりして、やってるんですがどうも真似できないです。ミルの問題なのか・・・?

それはともあれ、外国のガイドブックにでものっているのか?というくらい外国人の観光客が多いイメージがあります。

オーナーさんは焙煎技術を競う大会で日本で3位になっていて、外国の知り合いからたまーに豆が送られて来るらしく、運が良ければ定番以外の豆が飲めることも。

年に1回ゲイシャ豆もでます

NOZY COFFEE

ここのコーヒーはどれを飲んでも甘い!家で淹れても甘い! 夏はここでアイスコーヒーをかって世田谷公園のベンチで「あついー」ってやるのが結構好きだったりします。冬は店内でゆっくりと。

また、カフェにコーヒー豆をおろしてたりするので、そこでは美味しいコーヒーを飲むことができます。

tabelog.com 会社の近辺だとここです。ここはテイクアウトでコーヒーの注文だけも可能なのでたまに行きます。

全体的に渋谷近辺かつ山の手線の外側になりましたが、この3つにいつも行っています。美味しいコーヒーさいこーーー!

同期系スマホアプリのリリースサイクル・テストについて

この記事はCyberAgent エンジニア Advent Calendar 2015の12日目の記事です。

www.adventar.org

昨日はtoguriさんのVRを追いかけるゼミやってます でした。 360度動画がFacebookで見れるようになったり、コロプラさんが白猫のVR化や株式会社360Channelを設立したりとホットな技術。PlayStationVRもお披露目されましたし、盛り上がってるんですね〜! 明日は@yudpppさんです。

今日の記事では自分が携わっているスマホの同期アバターサービスで
どのようにリリースサイクルを回しているかを紹介したいと思います。

特に

  • リリースサイクルのボトルネックはどこか
  • リリースサイクルと強く結びついているテスト
  • バグなくリリースするために心がけていること
  • iOS/Android両プラットフォームリリースオペレーション

について触れていきます。

同期サービスが故に行っている、iOS/Android両プラットフォームの同時リリースオペレーションのノウハウは稀かもしれませんが、工夫ポイントでもあるので少し詳しく紹介させてください。

アバターサービスの技術スタック

フロント

  • 9割がCocos2d-xで実装
  • テキスト入力、ピッカー、アルバム取得などはネイティブ(Java/Objective-C)

サーバー

  • Node JS, Mongo, Redis

通信は同期系通信(発言、ユーザーの位置情報など)はMQTT、ユーザーのタップドリブンの通信はhttpsで行っており、シリアライズにmsgpackを用いています。
私は職種としてフロントエンドで、C++からUIKitやAndroidSDKにブリッジする部分やネイティブに依存する部分、例えばサードパーティSDK組み込みやPush通知、課金周りを主に開発してきました。

それもあって、Google PlayStoreやiTunes Connectをよく触っていたためリリースフローに各プラットフォームの仕様などを還元することがありました。

リリースフローについて

まずは、リリースフローについて紹介します。

おおまかなリリースフロー

f:id:matsuokah:20151212045055p:plain

↑はチームで実際に使っているガントチャートに近いもので、以下のことを管理しています

  • いつどのバージョンのどの機能がテスト可能になるのか
  • いつどのバージョンを申請するのか
  • いつどのバージョンをリリースするのか
  • 特筆すべきこと(iOSアプリの64bit対応やATS、IPv6対応のデッドなど外部要因であり無視できないもの)

また、このガントに載る機能の情報は要件定義が終了し、開発が進められる状態のものです。
チーム全体のスケジュールがここに集約されているため開発陣はもちろん、マスタデータの管理者やテストチームに共有されており、共通認識を持つことで円滑にテストまで行けるようになっています。

フローを説明すると

  1. staging環境のアプリを準備(タグ切り)
  2. staging環境にて仕様テスト、強制終了箇所が増えてないかのモンキーテスト
  3. Apple Storeにアプリを申請
  4. Google PlayStoreでβ公開
  5. Apple のレビューを待つ
  6. レビューが通ったら両OSのアプリを同時にリリースする

iOSのレビュー提出日を基準にスケジュールを組み立てる

ネイティブアプリはAppleのレビュー期間がボトルネックになります。言い換えれば、リリースが若干ながらアンコントローラブルということです。
それ故に、コントローラブルであるアプリの申請日を基準に逆算してスケジュールを組んでいます。

前回のリリースからいかに短い期間で申請を出せるかが リリースサイクルを早く回す為の重要なポイントとなります。

リリースサイクルを早めるメリット/デメリット

メリット デメリット
・ 新機能を早くみてもらえる
・テスト単位を小さくすることができる
・ バグの修正を早く
・ ユーザーにアプリを再認識してもらえる
・ わずかに離脱するユーザーがいる

圧倒的にメリットの方が大きいです。 特に注目したいのが「テスト単位が小さくすることができる」です。テスト単位、コード差分が小さいということは即ちリグレッションリスクを低くできる」ということなのです。

後は、PDCAが早く回せるのでその分アプリの改善をたくさんできるということになります。

また、ホームに埋もれていてもアップデートのバッジによってアプリを見てもらえるので、視覚的な副産物があります。(効果があるのかはわかりませんが笑)

1回のリリースサイクルは約2週間

Appleのレビューにかかるのは約7日、営業日換算で5日です。
更に申請をするまでに組み込む機能の仕様テスト及び、強制終了が増えてないかのモンキーテストを5日とっています。
(現状ではリグレッションテストが行えていないので今後の課題となっています。)

従って1回のリリースサイクルにかかる時間は最短で2週間になります。

定期的に申請までこぎつけるのはかなり骨が折れるので、Facebookが2週間に1度に必ず行っているiOSアプリの定期リリースは心から尊敬しています。

大きい機能をこのフローにのせるには

当たり前ですが、2週間単位のリリースサイクルとはいえ開発する機能によっては2週間の中に収まらない大きな機能が出てきます。

この場合は、トップダウン的に約1~3ヶ月にマイルストーンをざっくりとおいて、大枠が見えたところで2週間のスキームに落としこむという方法をとっています。 大枠はボトムアップ的に見えて来ますが、大体トップダウンのスケジュールに着地します。

また、このような機能は仕様が膨大である場合が多いです。つまり5日間のテストにも収まりません。

そこでdevelopment環境の仕様テストを行っています。

stagingと何が違うかというと、ガンガン開発中・仕様が盛り切っていないfeatureブランチのアプリだったり、ひとまず開発者が仕様を盛り込み終わったdevelopブランチのアプリだったりします。 サーバーにもテストすべき機能が盛り込まれたアプリをデプロイしてもらっています。

また、テストやデプロイするアプリの管理やテスト依頼などの細かいイテレーションはその機能の担当者がやっています。

development環境でテストすることで、仕様の定義漏れに気づくというメリットがありました。

開発者は意地悪なテストをしません。どうしても自分に都合の良いテストしかできません。なぜなら、その機能をどう使えばいいか知っているからです。

しかし、テスターさんはとりあえず同時タップしたり、SDを抜いたり、サスペンド&レジュームしたり、3G回線エミュレートしたり、電池が少ない状態にしたり、画像が数千枚ある端末でテストしたりします。そうすると、仕様が不明確な部分や、実装が漏れているエラー処理を浮き彫りにさせたり、ストレスがある状況での挙動がおかしい現象を見つけることで潜在バグの先手見つけたりすることができます。 それをstagingに前に済ませることで、差し戻しが激減され、結果的にstagingでの5日間のテストで収まるようになっています。

リリース

同期サービスならではである部分を含め、リリースについて紹介していきます。

まず特殊かもしれないポイントですが、AppStoreとPlayStoreでのリリース日を合わせる形にしています。 上位互換の無い機能がリリース、致命的なバグフィクスや運用上の都合で強制アップデートが必要になる場合、同時の方が都合がいいからです。

特に新機能はリリースと同時にキャンペーンやプロモーションを行うことが多いので、AppStoreとPlayStoreのリリースのラグを減らすことは運用上で必須事項となっています。

また、フロントのコードはCocos2d-xで実装されており、Android/iOS共にほぼ同じソースである以上、片方だけが不具合になるケースは稀なので同時リリースがリリースサイクルの観点からも最短であります。

強制アップデートの基準

  • 致命的なバグフィックス
  • 上位互換のない機能
  • プロモーションで必要になる機能の導入やアライアンスなど、運用上の理由

以上の観点で1つでも引っかかれば強制アップデートをするようにしています。それ以外では絶対に行いません。なぜなら、せっかくアプリを遊びに来ているのにアップデートをしないと遊べないのです。

ユーザーは今、この時、アプリを使いたいのです

Androidのアプリのβ公開

社内ではHockey Appを使っており、productionのアプリはダウンロード可能となっています。また、PlayStoreにアップロードするアプリと使っているKeyStoreが同じならば課金も同様にできます。

従って、わざわざβ公開をしなくても動作確認は可能です。

では、なぜβ公開をするのか。公開ボタンを押してからPlayStoreに反映される時間のラグを防ぎ、不具合が起きるリスクを少なくするためです。

直接製品版に公開 ベータ版から製品版にプロモート
1時間〜2時間 3分~15分

実測した結果、上記のようになりました。

ちなみにiOSは公開をポチってから5分~30分です。この取り組みのおかげでAndroidiOSのアプリ公開の時間差は30分以内に収まっています。

特に新機能はリリースと同時にキャンペーンやプロモーションを行うことが多いので、AppStoreとPlayStoreのリリースのラグを減らすことは運用上で必須事項となっています。

と、先程にも触れたように概ね、iOSAndroid同時リリースをする上でこのβ公開は欠かせません。

リリースオペレーション

具体的なオペレーションは審査が通った後からになります。ざっくりとまとめると

  1. レビュー通過のメールが届く
  2. 営業時間が残り4,5時間あれば当日、少なければ、翌営業日にまわす(障害対応可能時間を増やすため)
  3. iTunes Connectで公開をポチる
  4. Google PlayStoreでβアプリを製品版にプロモートする
  5. AppStore公開される
  6. Google PlayStoreに公開される
  7. 必要であれば強制アップデート
  8. アプリ内お知らせやキャンペーン、ツイッターでの告知などのプロモーションを公開する

という、フローで行っています。

特に5,6は今まで述べてきたように分単位で気をつけています。 そのための仕組として、リリースを検知してHipChatに通知をするにしています。

手で確認するのも面倒ですし、アプリで確認するとキャッシュが聞いていたり、Androidのβ版のテスターアカウントに関してはすでに公開されているので、製品版の公開タイミングはわかりません。

リリース検知の手法としてはGoogle PlayStore, AppStoreの公開日をスクレイピングして、前回と差分があればリリースと見なしています。(DOMが変わったらメンテが必要)

github.com

AppStoreの例となるスクリプトを載せておくので適当に御覧ください。

リリース祝いも兼ねて通知は少しだけ、待ち遠しくなるようにしています。最近はマンネリしてるかもですが。

PlayStore

f:id:matsuokah:20151212124521p:plain

ペリーキターーーーっ!

AppStore

f:id:matsuokah:20151212124525j:plain

波キターーーーっ!

f:id:matsuokah:20151212125003p:plain

この日は13:00に公開ボタンをポチってから Google PlayStoreが10分、AppStoreが26分だったようです。従ってこの日は16分の時間差で済みました。こんな感じで、少しテンションを上げてリリースしてます↑age↑(´∀`∩)↑age↑

まとめ

以上、弊社のとある同期系アバタースマホアプリのリリースサイクルについて触れてみました。

他人のお山である以上、リリースサイクルは完全にフレキシブルにはならないものの、コントローラブルなポイントを見つけて、 リリースサイクルに落としこむという事が肝になると個人的に考えています。

文字ばかりにはなってしまいましたが、最後までお読みいただきありがとうございました。

iPhone4からのiOSユーザーがメイン機をAndroidへの乗り換えた話

f:id:matsuokah:20151123163232j:plain

筆者はsimフリー機(iPhone6)をMVNOで運用していたが、docomoのXpria Z5を契約したという話。
乗り換えにあたって「契約まで」と「メイン機の移行」でしたことをまとめてみた。

乗り換えた理由

まず、乗り換えた理由から。理由は5つ

  • ハードウェア的にでできることが似通ってきた(カメラの高画質化、指紋認証など)
  • 両OSで使えるアプリが増えてきた
  • Apple垂直統合的な環境からAndroidへの乗り換えやすさがサポートされてきた
  • Felica(モバイルSuica, Edy, 会社の入退室カードキー統合)
  • 防水/防塵

iPhone4の頃Androidは便利なアプリはほとんどiOSにしかなく、
Androidは2.3でウェブページのピンチすら重くてブラウジングがままならず、ルートをとってオーバークロックが流行っていたが
今やハードウェアの高性能化とOSやアプリの改善により差がないといえる。

今では両OSでできることがほぼ同じだが、iPhoneにはないのが電子マネーや防水/防塵。
国内で生活する上で電子マネーヘビーユーザーの自分にとって決定的となった。

そして、家のメディア周りがSONYなのでXperiaを選んだ。(BRAVIA, PS4, nasne)
Xperiaオクタコア(コア数が8)となっており、処理重視4コア・省電力重視4コアという内訳。
処理重視と省電力重視のコアを組み合わせるのはハイスペックモデルのAndroid機ではスタンダードになっている。

契約

f:id:matsuokah:20151123192739j:plain

2015-2016冬モデルのXperia Z5(ドコモ)をヨドバシにて契約。
一括購入によるポイント付加や下取りの査定がゆるかったため、今後は契約はヨドバシですることにした。

家に眠っていたiPhone5(32G)を出した所、傷はそれなりにあったものの下取りは満額の22680円だったので。
また、ソフトバンクショップでは「MNPでの転出元simと使っている端末が一致しなければ引き取れない」と言われたので、ヨドバシではダメ元だったが引き取ってもらえた。

元々、Nexus 5をもっていたが、開発機として購入したため初期化したりOS Versionを上げたり下げたりするためメインとしては使えなかった。

乗り換えてはじめにした設定

ランチャ

f:id:matsuokah:20151123173435p:plain

初期設定ではDocomo標準の使いにくいランチャが設定されているので、まずはここから改善していく。

Nova Launcher Prime - Google Play のアプリNova Launcher Prime - Google Play のアプリ

Nova Launcherは売れてるランチャだけあって、あると便利な設定が揃っていて、安定している。

  • 細かなアイコンのレイアウト(グリッド/余白)
  • デスクトップでジェスチャの
  • 設定のバックアップ/インポート

Nexus5でいろいろ試していて、落ちるアプリがよくあったが、一番Nova Launcherが安定していた。

アイコンバッジ

f:id:matsuokah:20151123184148j:plain

iOSだとOSレベルでサポートされているアプリアイコンへのバッジはAndroidではサポートされていない。
これはランチャに依存している模様。従って対応のランチャをインストールするなり、その設定をする必要がある。

Nova Launcherの場合、デフォルトでバッジをつける設定ができる。
バッジ設定をOnにして、バッジプロバイダアプリを設定すればバッジが表示される。
デフォルトではNova Launcherの開発者が提供するプロバイダがあるが、Missed it!がNova Launcherではおすすめされている。
Missed it!は通知のサマリをウィジット化できるアプリで、デザインや表示フォーマット、サマリに加えるアプリなどをカスタマイズすることができる。

デスクトップ

f:id:matsuokah:20151123183456j:plain

Androidの場合デスクトップが起動時の画面でウィジットをおいたり、
アプリのショートカットを置いたりとカスタムできるところであり、Androidの醍醐味となる所。

iOSのホームがAndroidの場合、アプリドロワー(即ち、アプリ一覧)に近い。

ウィジット
  • 時計
  • Calendar
  • 天気
  • Missed it!
  • Edy残高
  • Suica残高
  • Trello Add Card shortcut

アプリショートカット

プリインストールアプリの無効化

3大キャリアあるある。不要なアプリのプリインストールの多さ。

これらを無効化しないと通知も鬱陶しいし、電池持ちが悪くなる気がしている。
そこでルート化なしで可能な範囲で一番最初にポチポチ無効化していった。

  • AR effect
  • エリアメール
  • 災害キット
  • ドコモクラウド
  • ドコモメール
  • Enchanted forest
  • File Commander
  • FMラジオ
  • 文字編集
  • NOTTV
  • ドコモアドレス帳
  • 音声レコーダ
  • テレビ(ワンセグ)
  • ドコモ音声入力
  • ドコモバックアップ
  • コンシェルジュ

他にもdマーケットなどオフにしたいものがあったが、オフの設定ができないようになっていた。
アンイストールできないアプリもあって非常に憤りを覚える^^;

移行したアプリ

1Password Comico DropBox Facebook Facebook Messenger
Gmail Google Analytics GoogleMap Googleフォト HipChat
IFTTT Instagram Kindle NewsPicks Pocket
PushBullet Skype Slack SmartNews SoundCloud
Trello Twitter WEAR Yahoo!乗換案内 Yahoo!天気
はてなブログ クックパッド スリープサイクル ヨドバシゴールドポイントカード 日経電子版 | 食べログ

よく使うもの棚卸しして移行したアプリたち。 本当に使いたいアプリは両OSにリリースされてるものが多く、iOSにロックインされることはなくなったな〜、と痛感。

  • iPhoneに溜まってた写真はすべてGoolgeフォトでバックアップ
  • 1PasswordはiCloud同期からDropBox同期に
  • 他のアプリはそれぞれのアカウントでログインすればいいためほとんど手間なく移行完了。
    特にGoogleアカウントログインのアプリはOSレベルでログインがサポートされてるので全く手間がない。

これで移行はできたと思われる。Androidもぬるさくになったし、インテントも便利。
iOSで惜しいのはポップアップの辞書くらい。

おまけ

f:id:matsuokah:20151123195254j:plain

「初期設定してください」という通知をタップしたらこの画面に飛んだ。
バックキーも聞かないし、インストールしか選択肢がない。キャリアまじこわい・・・

kindleでライトに読めるソフトウェア開発のためのタスク管理・マネジメント本まとめ

本の選び方

タスク管理本は管理の対象がどのくらいの規模なのかを自分に問いかけてから選ぶと失敗しないと思います。

つまり、管理の対象は1人(自分)のをするのか、1,20人未満小規模のチームなのか。規模の大きさによってフレームワークや起こりうる問題などが違ってくるため、自分が何を求めているのかを分析したうえで選ぶ必要があります。

読んでよかったkindle本を、規模や対象に分けてメモ。

自分のタスク管理

図解 ミスが少ない人は必ずやっている[書類・手帳・ノート]の整理術

仕事を円滑にすすめる上での情報の整理術のTIPSたちが詰まっている本。一見、デスクワークしてる人向けっぽいような表紙ですが、仕事をしている人なら誰でも使える技を紹介してくれています。

タスク管理入門本としておすすめです。 

スマホ時代のタスク管理「超」入門

肌身離さずはいられないスマホの活用を前提としてフレームワークがしっかりと書かれています。リマインダーやカレンダーなどのツールを使い始めた頃に読むと目からうろこが落ちる本。具体性があるので、すぐ使えるノウハウが詰まっています。 

ひとつ上のGTD ストレスフリーの整理術 実践編――仕事というゲームと人生というビジネスに勝利する方法

kindle本ではないですが、更にタスク管理を徹底したいと思った時、部長クラスの上司におすすめされて読んだら役立った本なので紹介します。GTD(Getting Things Done)と呼ばれるフレームワークに準拠して書かれていて、小さいTipsではなく、1週間から1ヶ月単位の長期的な習慣づくりをしたい人におすすめ。タスク管理という概念や人が怠惰になる原因など、本質的な内容が載っています。 

チームのタスク管理

SCRUM BOOT CAMP THE BOOK

スクラムの入門本でちょうどセール中。2,3時間で読めるにしては内容が濃いです。ケースバイケースな問題に直面した時にどう切り抜けていくか?というストーリーが含まれていて、文章で淡々と解説されるよりも説得力を感じました。

スクラム初心者から中級者にかけて、まずは読みたい1冊です。 

カンバン: ソフトウェア開発の変革

最近最高純利を更新したトヨタカンバン方式をソフトウェア開発に還元した本。どうしてもスクラムではカバーしきれない柔軟性や組織的な仕組みづくりの補強として読みました。

ボトルネック見える化→解消するための基本的な考え方から、実践例が載っていてます。

エッセンシャル スクラム

辞書的存在なエッセンシャルスクラムスクラムをやっていると言語化しにくいが違和感を感じるポイントやジレンマがでてきます。それらの根本はどこにあるって、なぜ違和感やジレンマを感じるのかという概念的な解説が書かれています。フレームワークでカバーできないところを判断する一つの視点として役立つ本でした

部下のコーチング・行動科学

3分間コーチ ひとりでも部下のいる人のための世界一シンプルなマネジメント術

マネジメントは、心理学的側面からアプローチするとすんなりと物事な進むことがあると感じた1冊。どうしてもフレームワークや仕組みでもカバーしきれないところが出てきますが、それを話し方・対応の雰囲気などで改善していくためのノウハウが書かれた本。一人でも部下がいるならおすすめです。

短期間で組織が変わる 行動科学マネジメント

4章、5章がおすすめ。人のやる気に関わるところを論理的に解説されていて、自分にも当てはまるところがちらほら。コーチングでより結果を出すためには?というところがフレームワークと合わせて紹介されている本です。

まとめ

結局自分のメモ代わり的に書いてしまい、ライトに読める本ばかりではなくなってしまいましたがぜひ読んでみてください。

Webセキュリティの読み物

徳丸浩のWebセキュリティ教室

徳丸浩のWebセキュリティ教室

徳丸本がkindleで、出てたのでメモ。単行本は10月にでてます。

ポイント

  1. 3章構成(概要→攻撃手法→事例)となっており、読み物として要所とトレンドを抑えた内容となっている
  2. 特に3章では具体例を14も列挙されています。列挙されている例で言うと、「脆弱性の責任訴訟問題」、「パスワードの定期更新の有効性の検証」など

また、(徳丸さんのブログ)http://blog.tokumaru.org/2015/10/web1022.htmlでは

本書は書きおろしではなく、日経コンピュータ誌に連載したエッセイを、ほぼそのまま並べ直した形となっています。前著「安全なWebアプリケーションの作り方」のようながっつりした技術書ではなく、もう少し気楽な読み物として、技術者以外の方々にも読んでいただける内容になっている…と思います。

と、紹介されています。

セキュリティをガッツリ学びたいなら...?

徳丸さんといえば体系的に学ぶ 安全なWebアプリケーションの作り方が有名。

この本は

  1. 脆弱性とは何か
  2. なにが脆弱性になりやすいか
  3. どのように対処すべきか
  4. どのようにテストすべきか

と、セキュリティに関する勘所が実践形式かつ段階的に紹介されていて、1回流せばいやでも勘所がつきます。 対策のノウハウをつけることもさながら、観点を持っておくだけで実装の視野が広がる一冊となっているのでおすすめです。

体系的に学ぶ 安全なWebアプリケーションの作り方