技術選択とQCDのトレードオフという結論がない話

経緯としては受託開発会社にiOSアプリの開発を依頼したら、Objective-C(Obで作ると言われて「え?Swiftじゃないの?」とエンジニア陣がざわついた。

同僚とオンライン・オフラインで話してたけどこれは難しい。iOSアプリ開発には詳しくないけど、技術的な制約がないのにObjective-Cかとなるのはすごいわかる。Java8の時代にこれからJDK1.4で開発しなさいと言われたらFXで有り金全部溶かした人の顔になる。AppleがこれからSwiftを使ってねと言ってて、これからObjective-Cを書ける人も少なくなってくる。書ける人が少なくなるということは、メンテコストも高くなる。

ただ、相手の会社からしたら、今のメンバー構成でQCDを守るためにはこの選択が最良と判断したのだろう。相手のスキルとかは知らないが、会社にノウハウが溜まってない技術をお客のサービスに納品するというのはリスクが高い。内製開発と受託開発ではそもそもビジネスとしてのゴールが違うのでどちらも間違ってないから余計辛い。(もちろん最初に「この技術」でという制約があれば話が別だけど今回はなかった)

言語ではないが自分もそれまで使ったことがない技術をお客のサービスにいれたことがあった。新しい技術を使わないと問題を解決できない可能性があることを伝え、技術検証も含めてスケジュール・費用はきちんと頂いて仕事をした。

自分は検証とか好きなので自宅で素振りして会社にフィードバックしてたがそれがすぐ使えるかというとそういうわけではない。ビジネス・技術の制限事項や、そもそも今のチームで運用ができるのかというところまで考える必要がある。明日自分が倒れたらコスト・リスクが高くなる技術はみんなを不幸にする。それをなくすためにもスケジュール・費用は必要なものなのだ。それがないときは出してないものは成功するか失敗するかのスタートラインにも立ててないので、出してからその負債を返すか考えたほうがいい気がしてきた。今回は負債が大きすぎるのと、それをやると後辛いんだよなぁ...

ああ、結論がない。

プロダクトマネージャーカンファレンス2016に参加してきた

プロダクトマネージャーカンファレンス 2016 | 10/24~10/25 に参加してきました。カンファレンス内容とかは動画・スライドが上がると思うので、そちらを参考にいただければと思います。(業務連絡:社内向けには多分別途書きます)
2016/10/24(月)25(火) Japan Product Manager Conference 2016 #pmconfjp - Togetterまとめ

謝辞

2日目では1日目のフィードバックを受けて素早い改善がされてました。これがプロダクトマネジメント

なぜ参加したのか?

エンジニアとしてプロダクトマネージャー(PdM)がどういう思考をもっているのかというのを知って幅を広げたかったというのが一番になります。会社にはPdMはいないのですが、部分部分では思考や考え方、手法が使えてそれをうまくフィードバックできないかなと考えたためです。あとは、色々な記事で拝見する及川さんを見たかったというミーハー心は多分にありましたw

参加目的達成できた?

達成できました。明日からPdMを作るということはできないですが、エンジニアからアプローチしやすい内容もあった(例:最初にKPIを決めてその結果を計測する)ので、そういうところから入っていくのもいいのかもしれないかなと思いました。

ちなみに楽天の齊藤さんに個別で「もし最初のPMを置くとしたらどのようにしたらよいですか?」と質問したら、「すでにPMがいる外部の会社に3〜5年出して修行させる。難しいのであれば本を読んでその通りにやってみる」とおっしゃってました。このセッションは本当によかった…

感想

セッションの話を聞いていると各社でそれぞれやり方は違っていて正解・定石はない。考えたら会社のフェーズ・規模・文化が違うからそれをひとまとめにできないね。と言うのが改めてわかりました。ただ、共通項もあって

  1. プロダクトに愛情・熱意を持つ
  2. ユーザ・ものづくりへの理解を示す
  3. インパクトがでるもの・ユーザにささるものをつくる
  4. そのためにも目標を立ててその結果を数字として計測する
  5. 計測した数字をすぐ見れるようにする
  6. 会社目標、事業目標、個人目標をつなげてきちんと落とし込む
  7. 決断をする、信頼を得る、ビジョンを言語化して(ドキュメントにおこして)共感してもらう

というところが、各セッション毎にまとめてた自分のメモに書いてました。 会場で話を聞いてるときは文脈があるので伝わるのですが、箇条書きに書くとなんか当たり前の事を言ってる感じになりますね。明日社内向けにコンフルに書くつもりなのですが正確に伝えられるのか心配になってきました。

楽天の齊藤さんのセッションでみんなが共有できるドキュメントが大事でこれがないと必ず手戻りする。まずは理想をドキュメント化する、ヒット性のものを作るのであればPdMはいらない。まずは理想をもってこい。できるできないはその後に考える。というのが一番印象になりました。ドキュメントを各フェーズに書いてるとおっしゃってたので、各フェーズのドキュメントが矛盾なく作られてるのでしょう。

アンカンファレンスで話した

同僚も参加してたので「話してみたら?」とプッシュしてもらい、ちょうど会社で議論真っ最中のサービスコンセプトについて話してきました。弁が立つほうではなく、緊張しやすいので社内外含めてこのような形で話すことがほとんどなく、アンカンファレンスへの参加した記憶がないとおもうので、色々空気読まずにディスカッション形式でやってみたんですがよかったんでしょうか。

あと議論してる途中で時間が来てしまって尻切れトンボみたいになったのにその後のNetworking Partyで捕まえられない方がいてすいませんでした。

utf8_unicode_ci

全角と半角を区別する

create table test (
  id int PRIMARY KEY ,
  name varchar(255) COLLATE utf8_unicode_ci,
  title varchar(255)
);
INSERT INTO test(id, name, title) 
VALUES (1, 'abc', 'abc'),(2, 'ABC', 'ABC'),(3, 'ABC', 'ABC');

結果

mysql> SELECT * from test where name ='abc';
+----+-----------+-----------+
| id | name      | title     |
+----+-----------+-----------+
|  1 | abc       | abc       |
|  2 | ABC       | ABC       |
|  3 | ABC    | ABC    |
+----+-----------+-----------+
3 rows in set (0.01 sec)

mysql> SELECT * from test where title ='abc';
+----+------+-------+
| id | name | title |
+----+------+-------+
|  1 | abc  | abc   |
|  2 | ABC  | ABC   |
+----+------+-------+
2 rows in set (0.01 sec)

ridgepole 0.6.4 メモ

実戦で使えるように素振り

URL

https://github.com/winebarrel/ridgepole

install

gem 'ridgepole'
# スキーマにoptions(ストレージエンジンの設定など)をつける
gem 'activerecord-mysql-awesome'

エクスポート

すでにテーブルがある場合はexportする.

ridgepole -c config/database.yml --export -o db/schemas/Schemafile \
--dump-with-default-fk-name --split --enable-mysql-awesome
  • --dump-with-default-fk-name Railsの場合は外部キーの名前がfk_rails_xxxxになるのでそれもエクスポートする。applyするときにも必要
  • --split テーブルごとにスキーマファイルを分ける
  • --enable-mysql-awesome create文にoptionをつける

ちなみに limit:4 は4バイ

create_table "tasks", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" do |t|
  t.integer  "project_id",  limit: 4,     null: false
  t.string   "title",       limit: 255,   null: false
  t.text     "description", limit: 65535
  t.integer  "creator_id",  limit: 4,     null: false
  t.integer  "updater_id",  limit: 4,     null: false
  t.datetime "created_at",                null: false
  t.datetime "updated_at",                null: false
end

add_index "tasks", ["project_id"], name: "fk_rails_02e851e3b7", using: :btree

実行

runするときには --dry-run をはずす

ridgepole -c config/database.yml --apply \
--dry-run -f db/schemas/Schemafile \
--dump-with-default-fk-name

比較

通常の比較

DBとファイルを比較

ridgepole --diff config/database.yml db/schemas/Schemafile \
--dump-with-default-fk-name

ロールバック的な

ridgepole --diff config/database.yml db/schemas/Schemafile \
--reverse \
--dump-with-default-fk-name

AWS CodeDeployで遊んでみた

会社でCodeDeployを使ってたけど、使ったことなかったので遊んでみた。

AWS CodeDeployとは?

https://aws.amazon.com/jp/codedeploy/ より

AWS CodeDeploy は、Amazon EC2 インスタンス、およびオンプレミスで稼働するインスタンスを含む、さまざまなインスタンスへのコードのデプロイを自動化するサービスです。

シンプルなデプロイであればこれで十二分に思える。デプロイを自動化してくれるサービスなのでCI的なことをやりたいのであれば、CodePipelineとかつかうんだろう。

全体図

GitHubにpushするとCircleCIが走るので、テストが通ったらアプリをS3にput後デプロイする。 リージョンは安いからus-east-1

f:id:hs_hachi:20160911005810p:plain

内容

一部でも読んだドキュメント

IAMユーザとロールの作成

  1. APIを叩くためのユーザ(ユーザ名:codeDeployUser)を作成する(このユーザのaccess id をCircleCIに管理画面で登録する) Step 1: Provision an IAM User - AWS CodeDeploy をみてロールを適切に付与する。やりたいことにもよるが,最低限S3とCodeDeploy関連があればOK
  2. CodeDeployで実行するときに必要なデプロイグループ用ロール(ロール名:CodeDeployServiceRole)を作成する
    1. アクセス許可の管理ポリシーに AWSCodeDeployRole を追加する
    2. 信頼されたエンティティを追加する
  3. EC2を作るときに設定するIAMロール(ロール名:CodeDeployDemo-EC2)を作成する
    1. 管理用ポリシーに AmazonEC2FullAccess を追加した(ここは多分ちゃんと絞るべき)
    2. インラインポリシーにポリシー(ポリシー名:ec2-role-permission)を追加
    3. 信頼関係を追加する

CodeDeployServiceRoleの信頼関係

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "codedeploy.us-east-1.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

CodeDeployDemo-EC2のインラインポリシー

 {
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:Get*",
                "s3:List*"
            ],
            "Resource": [
                "arn:aws:s3:::aws-codedeploy-us-east-1/*"
            ]
        }
    ]
}

CodeDeployDemo-EC2の信頼関係

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

S3バケットの追加

特定者からのみのアクセスをうけるように、バケットポリシーにユーザ codeDeployUserとロールCodeDeployDemo-EC2を追加した。

EC2ユーザ作成

2台以上で作ること。

  1. インスタンスを作成するときにIAMロールCodeDeployDemo-EC2を忘れない
  2. CodeDeployのグループの対象インスタンスとなるようにタグを作成するときにキー:Role, 値:WebAppという名前をつけた
  3. AWS CodeDeploy agentをインストールする

CodeDeployの設定

途中で失敗してもアプリの内容はロールバックしないので注意(正常にデプロイしたものがあればそれはそのまま)

  1. アプリケーションを新規で作成する
    • アプリケーション名:sample-app (ここは circle.ymlで使う)
    • デプロイグループ名:SampleAppsGroup (ここは circle.ymlで使う)
    • EC2インスタンスタグ:Role:WebApp
    • サービスロール ARN:CodeDeployServiceRole を選択した
    • デプロイ設定:CodeDeployDefault.OneAtATime ここはお好み

CircleCIの設定

  1. codeDeployUserのaccess Key IDとSecret Keyを登録する

アプリの設定

  1. circle.yml にデプロイの設定を記載
  2. appspec.yml にcodeDeployで実行する内容を記載する。(この辺はあまり調べられてない)

circle.ymlの内容の抜粋

deployment:
  staging:
    branch: master
    codedeploy:
      sample-app: # ここはアプリケーション名と合わせる
        application_root: /
        region: us-east-1
        deployment_group: SampleAppsGroup # ここはデプロイメントグループと合わせる
        revision_location:
          revision_type: S3
          s3_location:
            bucket: バケット名
            key_pattern: my-sample-app-{SHORT_COMMIT}-{BUILD_NUM} # キーパターンは適当

appspec.ymlの内容

version: 0.0
os: linux
files:
  - source: /
    destination: /usr/local/demo-app # アプリ配置先
hooks:
  BeforeInstall:
    - location: deploy/before_install.sh # インストールする前の実行するシェル(ELBから外すとか..)

その他

  • /var/log/aws/codedeploy-agent/codedeploy-agent.log にログが出るので途中で失敗した時は確認する

Jenkins2.0 + http2をつかってみた

Jenkinsには足を向けて寝れないほど毎日使ってる人間なので、めでたくJenkins2が出たのでやってみた
ついでにhttp2使ったらどのぐらいはやくなるのかな?というみたかった。
あとLet's Encryptもつかってみよう

環境

  • jenkins 2.6
  • nginx 1.11
  • AWS(AMI ami-f5f41398) t2.micro US East (N. Virginia)リージョン

結論

http2にすると大体0.5秒〜1.0秒ぐらい速くなった。体感的には若干速くなったと感じる程度。
積極的に使っていっていいと思います


jenkins2 using http1(ssl)


jenkins2 using http2

ざっくりした環境構築

Let' Encryptのインストール

gitを入れる必要がある

git clone https://github.com/certbot/certbot
cd certbot/
./certbot-auto --debug
./certbot-auto certonly --standalone -d <domain>

nginxのインストール

/etc/yum.repos.d/nginx.repo に以下を追加してから yum install nginx でインストール

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/mainline/centos/6/$basearch/
gpgcheck=0
enabled=1
priority=1

nginx.confの一部

upstream backend {
    server 127.0.0.1:8080;
}

server {
    listen       443 ssl http2 ;
    listen       [::]:443 ssl http2;
    #listen       443 ssl ;
    #listen       [::]:443 ssl ;
    server_name  <domain;
    root         /usr/share/nginx/html;

    gzip on;

    ssl_certificate "/etc/letsencrypt/live/<domain>/fullchain.pem";
    ssl_certificate_key "/etc/letsencrypt/live/<domain>/privkey.pem";
    # It is *strongly* recommended to generate unique DH parameters
    # Generate them with: openssl dhparam -out /etc/pki/nginx/dhparams.pem 2048
    #ssl_dhparam "/etc/pki/nginx/dhparams.pem";
    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout  10m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers AESGCM:HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP;
    ssl_prefer_server_ciphers on;

    # Load configuration files for the default server block.
    include /etc/nginx/default.d/*.conf;

    location / {
        proxy_pass http://backend ;
        proxy_redirect default;

        proxy_set_header   Host             $host;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
        proxy_max_temp_file_size 0;

        #this is the maximum upload size
        client_max_body_size       10m;
        client_body_buffer_size    128k;

        proxy_connect_timeout      90;
        proxy_send_timeout         90;
        proxy_read_timeout         90;

        proxy_buffer_size          4k;
        proxy_buffers              4 32k;
        proxy_busy_buffers_size    64k;
        proxy_temp_file_write_size 64k;
    }

    error_page 404 /404.html;
        location = /40x.html {
    }

    error_page 500 502 503 504 /50x.html;
        location = /50x.html {
    }
}

Jenkinsのインストール

sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
sudo rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key
yum install jenkins

久しぶりに技術的なことを書けて楽しかった