実装のバリエーションを増やすために

最近仕事をしながらこういうことを思っていて。

その難しさの要因の1つに、自分の中に実装のバリエーションが少ないことがあるんじゃないか、と思っていろいろ考えてみたのでまとめてみる。 筆者が Android アプリメインであるため、Android を例にご紹介。題材は最近はまっている Dropbox Paper。

play.google.com

実装のバリエーションとは

ここではエディタなどのコンポーネント、そのコンポーネント内の細かい挙動やアニメーションなどを指す。

実装のバリエーションを増やすと何が嬉しいの?

今いるチームでは、デザイナーがプロダクトとしての世界観を維持しつつ a11y などを意識してデザイン。エンジニア(自分)はそれを見つつ Material Design により準拠できるようにデザイナーと話し合いながら実装する形で進めている。

その中で、デザイナーから「こういうデザイン実現したいんだけどできそう?」という質問によく遭遇するのだが、今はそれに対して調べないとわからないことが多い。バリエーションを増やせばスパッと答えることができるし、バリエーションが多いともっと UX 的に良いデザインが提案できる(かもしれない)と思った。

やはりエンジニアとしてアプリを作っている以上、ユーザーに価値を届けられることが一番の目的であるので、その価値を届けるための近道ができるようになるのが嬉しい

バリエーションを増やす方法

Play Store で配信されているアプリ

Dropbox Paper のように配信されているアプリは、だいたい設定画面あたりにオープンソースライセンスへの導線が存在する。Dropbox Paper だとここ。

f:id:rnitame:20171112184941p:plain

それを活用して、知らなかった OSS 等を見つけたらひたすら触ってみる。ただただ触っても楽しくないのでいろんなアプリをカテゴリごとに分けて、それぞれのカテゴリから1つアプリを選んで比べながら触ってみるGoogle Play Store で配信されているアプリは必ず1つのカテゴリーに属しているため、それで判断すると良い。例えば、Dropbox Paper は仕事効率化(PRODUCTIVITY)だった。

f:id:rnitame:20171112183156p:plain

Dropbox Paper を触ってみると、 このページは ViewPager で作ってるのかなーとか。

f:id:rnitame:20171112184935p:plain

このページだとタブは TabLayout か何かで、FAB があって、RecyclerView か ListView でリスト出しつつ、EditText の onTextChanged が発火したときにリストの内容を変更するのかな?とか考える。

f:id:rnitame:20171112184939p:plain

OSS

OSS は build.gradle を見てビルドして触る。 基本ストアで配信されているアプリと同じ要領だが、気になった挙動があればコードを見ることができるのでより詳細に把握できる。 最近は各地で Droidcon が開催されているので、それの公式アプリやスライドで使われたリポジトリをよく見ている。

github.com

github.com

github.com

まとめ

実装のバリエーションを増やすために、いろんなアプリを触ってみようねというお話。 最近 Kotlin が流行ってるけど、そういう言語も含めて実装のバリエーションを常にアップデートするようにしたい。

iOSDC Japan 2017 で「AutoLayout と友達になる方法」というタイトルで登壇しました & 当日スタッフをやりました

iOSDC Japan 2017 に登壇者+スタッフとして参加しました。

登壇者として

AutoLayout に関する話をしました。 CfP 眺めていたら AutoLayout のメカニズムに関する話があって、うわ〜〜絶対そっちの方が面白いやん!!って思ってたんですが無事採択されました(よかった) 初めて AutoLayout を触る人向けに、抑えておくと AutoLayout 理解しやすいかもと思うポイントを紹介する内容です。

スライドはこちら

speakerdeck.com

TrackA が MAX 600 人入れる会場で緊張しっぱなしだったのですが、思った以上にたくさんの方に聞いていただいて、質問もたくさんいただいてうれしかったです。 みんな AutoLayout で苦労してるんだなぁと実感しました。

スタッフとして

主に TrackC の司会やタイムキーパーを担当していました。

普段は Android をやってますが、スマフォアプリのユーザーと密接になれる関係が大好きなので Android に限らず iOS 開発もやっています。 iOS をやり始めたのは今年に入ってからですが、いろいろ調べる中で iOSDC で発表された資料たちに救われたのもあり、恩返しの意味も込めて参加させて頂きました。

感想

登壇者として

自分の理解が浅かったところもあって、質問にうまく答えられなかったのが悔しかったです (´・ω・`) 実は CfP を 2 つ応募していて、通らなかった「iOS アプリ開発における CLI の世界」についてリジェクトコンで話します。今度は倍の 30 分。 今回の反省点を活かしてよりよいプレゼンができるように準備したいと思います。

iosdc-reject-conference.connpass.com

それと開発意欲がすごい湧いてきたのでさっそくアプリを作り始めました。

github.com

やっていき!!!!!!!! iOSDC で得たでかいモチベーションを絶やさないようにがんばります。1 年またがんばって CfP 応募します!!!

スタッフとして

こういったカンファレンスのスタッフは PHP カンファレンスに続いて 2 回目だったのですが、とてもフレンドリーな雰囲気&方々でとても馴染みやすかったです。 睡眠時間がいつもより少なくて大変なところはありましたが、みんなで作り上げる楽しさを感じることができました。 来年も開催されればスタッフやりたいなと思っています。

スタッフの皆さん、参加者の皆さんお疲れさまでした!!!!!

goreleaser と Travis CI で Golang のバイナリ配布を自動化する

Golang で作ったツールを配布したいとき、ビルドして zip なりにまとめて GitHub の Release ページなり Homebrew で公開する必要がありますが、毎回手作業でやるのは面倒です。 そこで goreleaser と Travis CI を使って自動化してみました。

goreleaser の README にサンプルが載っていることと、GitHub と連携できて楽という理由で Travis CI を使っています。

goreleaser とは

Golang のバイナリを速く、簡単にデリバリーできるツールです(リポジトリ見てください) github.com

手順

Travis CI で GITHUB_TOKEN を設定

f:id:rnitame:20170719013612p:plain

権限を repo だけつけた Personal access token を生成して設定します。

yml を書く

.goreleaser.yml はこんな感じ。

# Build customization
builds:
  - binary: daily
    goos:
      - windows
      - darwin
      - linux
    goarch:
      - amd64

# Archive customization
archive:
  format: zip
  format_overrides:
    - goos: windows
      format: zip

# Release customization
release:
  github:
    owner: rnitame
    name: daily

brew:
  github:
    owner: rnitame
    name: homebrew-daily

  homepage: "https://github.com/rnitame/daily"

  install: |
    bin.install "daily"

builds でクロスビルド、archive で zip に固める、release で固めた zip をリリースするための設定をしています。 brew では homebrew-tap でも使えるようにするための設定をしてます。 設定自体はちょっとわかりづらいんですが、goreleaser のリポジトリにある yml を見ると参考になるかと思います。

.travis.yml はこんな感じ。

language: go

before_install:
  - go get -u github.com/Masterminds/glide

script:
  - glide install
  - go test -v

after_success:
  - test -n "$TRAVIS_TAG" && curl -sL https://git.io/goreleaser | bash

今回バイナリ配布した daily というツールがあるんですが、そこで glide を使っているので先にそれをインストールします。 そして、script でライブラリをインストールするなり、テストまわすなり、カバレッジ取るなりいろいろして、成功したあとに goreleaser を起動する。といった具合です。

before_install の go get のところは、curl https://glide.sh/get | sh でやってみたんですが linux amd64 に対応しておらずビルドがこけるのでこのようにしています。 参考 ↓

github.com

タグを打つ

上記の $TRAVIS_TAG はタグを打ったときに値が入る Travis CI の定数です。なのでタグを打ったときだけ自動でバイナリを生成してリリースします。

結果

タグを打つとビルドが走って、goreleaserbot がリリース作ってくれたり homebrew-tap のリポジトリにコミットしてくれます。

リリース↓

f:id:rnitame:20170719013923p:plain

homebrew-tap ↓

f:id:rnitame:20170719011724p:plain

便利!!

さいごに

自動化ってすばらしい 🙌

サイバーエージェントに入社します

近況です。

f:id:rnitame:20170627182618p:plain

前職であるアイスタイルを 6/30 付けで退職しました。 アイスタイルは新卒入社した会社で、内定者アルバイトを含めると1年4ヶ月、その前のインターンも含めると2年弱お世話になりました。

やっていたこと

元々 Web サービスがメインの会社なので、アルバイトの時から php (Laravel とか CakePHP とか) をずっと書いてました。 主に社内ツールを作っていて、Laravel で基本作っていたところを Angular と TypeScript 使ってフロント実装する経験もさせていただきました。(確か Angular を使ったプロジェクトは社内初) 社内ツールが終わったあとはアプリのプロジェクトへ。ごくまれに Android もやりつつ、iOS アプリを主に担当しました。

Android は経験あったんですが、Web と iOS の経験がほとんどなく。にもかかわらず優しく教えて頂いた&あれやりたいこれやりたいっていう我が儘を聞いてくださった部署の皆さんに感謝です。

本当にありがとうございました。

辞める理由

うまく言葉にできなかったのでオフラインで聞いてください (:3 」∠) 簡潔に言うと前の会社に不満はなかったのですが、オファーいただいてお話を聞いたときによりレベルアップできそうと思ったのと、よりサービスと密接に関われそうだなと思ったのが理由です。

次は?

次は7/3からサイバーエージェントで働きます。新規事業で Android エンジニアをやる予定です。 フル Kotlin の機運が高まってきていて Kotlin 漬けになりそうでめちゃくちゃ楽しみです。

ほしいものリスト

置いておきます。 amzn.asia

その日の GitHub の Activity を拾って表示する Daily を Golang で作った

daily とは?

golang 製の CLI で、コマンドを叩いた日の GitHub の Activity を出力します。

会社で日報を書いている
↓
その日やったこととして、〜の機能を実装した、〜は途中、レビューした、などなどを書く
↓
量が多いと何をどこまでやったか思い出せない、書くのも面倒になる
↓
GitHub の履歴から自動生成すればいいんじゃないか?

といった感じで思いついたのが実装を始めるきっかけ。

インストール方法

go get か Homebrew で。

# go get
$ go get github.com/rnitame/daily

# Homebrew
$ brew tap rnitame/homebrew-daily
$ brew install daily

f:id:rnitame:20170627163203p:plain

↑ Homebrew でインストールするとこんな感じになる

使い方

GitHubトークンをセット

$ git config --global "github.token" xxxxx

セットした状態で daily を叩くと結果が出力される
出力例はこんな感じ。

f:id:rnitame:20170627163208p:plain

特定の organization のイベントだけほしいとき

-org オプションをつけることで可能。

$ daily -org xxxxx

golang っぽい書き方を目指す

1つのファイルに全ての処理を勢いで書き殴っていたが、テストを書こうとした瞬間にものすごい面倒くささが押し寄せてきた。(何か処理を追加するときもだいぶ面倒。。) そのため、この記事を見ながらファイルを分割してテストを書く。

もっと使いやすいツールに

PR や issue がどういうものなのかわからなかったので、表示するようにした。

最後に

まだヘルプページがないので充実させたい。issue もちょっと残ってるのでなくしたい。

PR などなどお待ちしてます! https://github.com/rnitame/daily

Laravel プロジェクトに Angular を導入してみた

はじめに

Laravel のプロジェクトに Angular を導入してみたのでご紹介。 Angular (TypeScript) を Webpack でトランスパイルして、blade で表示する流れ。

環境

  • Laravel 5.2
  • Angular 4.0
  • TypeScript 2.1
  • Webpack 1

すでに Laravel をインストールして、new project した前提で話を進める。

Laravel からいらないライブラリやファイルを削除する

Laravel の JS や CSS のビルドは、gulp で行われているのでそれに関係するライブラリやファイル群を削除。

 gulpfile.js
 gulp
 gulp-environments
 gulp-if
 gulp-load-plugins
 gulp-notify
 gulp-plumber
 gulp-postcss
 gulp-rev
 gulp-sass
 gulp-sourcemaps
 gulp-typescript
 gulp-uglify
 gulp-watch
 gulp-webpack
 lite-server

Angular / TypeScript などなどインストー

Angular を TypeScript で書くのでインストール。他、ビルド等で必要なものも。

@angular/common
@angular/compiler
@angular/core
@angular/forms
@angular/http
@angular/platform-browser
@angular/platform-browser-dynamic
@types/core-js
@types/jasmine
@types/karma
@types/lodash
@types/node
@types/webpack
@types/webpack-env
core-js
es6-promise
es6-shim
hammerjs
jasmine-core
karma-typescript
rxjs
systemjs
zone.js
tslint
tslint-loader
css-loader
karma
karma-jasmine
karma-phantomjs-launcher
karma-sourcemap-loader
karma-webpack
phantomjs-prebuilt
style-loader
ts-helpers
ts-loader
typescript
webpack

Angular 用のディレクトリを掘ってコンポーネント配置

public/ の中に入れてしまうか、resources/ の下に入れてしまうか迷った結果、ルートに angular というディレクトリを掘ってそこに集約。これはどこでも良いと思うが、わかりやすさを重視した。 コンポーネントの配置は、基本的に Angular の Style Guide に乗っ取った。components/ の中はどのコンポーネントが何を内包しているかわかりやすくするため、階層型にしている。

├── components
│   ├── footer
│   │   ├── footer.component.html
│   │   ├── footer.component.scss
│   │   ├── footer.component.spec.ts
│   │   └── footer.component.ts
│   ├── header
│   │   ├── header.component.html
│   │   ├── header.component.scss
│   │   ├── header.component.spec.ts
│   │   └── header.component.ts
│   ├── main-area
│   │   ├── xxx/ (子コンポーネント)
│   │   ├── main-area.component.html
│   │   ├── main-area.component.scss
│   │   ├── main-area.component.spec.ts
│   │   └── main-area.component.ts
├── config
│   ├── config.ts
│   ├── development.ts
│   ├── production.ts
│   └── staging.ts
├── environments
│   ├── environment.prod.ts
│   └── environment.ts
├── main.ts
├── polyfills.ts
└── services

Webpack や TypeScript の設定

tsconfig.json はいろんな設定をパクった結果、今のものに行き着いた。tsconfig.json の設定如何では、コンパイル通らなくなったりコード書きづらくなる(any 周りなど)のでドキュメント見ながら設定することをおすすめする。 また、webpack.config.js は、development と production で分岐。 development では sourcemap を出してデバッグしやすく、production ではなるべくバンドルを圧縮させるプラグインを使用。 webpack-dev-server を使ってみたのですが、ルートディレクトリに index.html がないと起動しないらしく、webpack –watch で代用。

tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "allowJs": true,
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "declaration": false,
    "removeComments": true,
    "noImplicitAny": true,
    "noImplicitReturns": true,
    "compileOnSave": false,
    "types": [
      "node",
      "jasmine"
    ],
    "lib": [
      "es2015", "dom"
    ]
  },
  "typeRoots": [
    "node_modules/@types"
  ],
  "exclude": [
    "node_modules",
    "vendor"
  ]

webpack.config.js

'use strict';

var webpack = require('webpack');
var path = require('path');
var isProd = process.env.NODE_ENV === 'production';

var config = {
  devtool: isProd ? 'eval' : 'inline-source-map',
  entry: {
    'app': './angular/main.ts'
  },
  output: {
    path: path.resolve(__dirname, 'public/js'),
    filename: 'app.js',
    chunkFilename: (+new Date) + '.app.js'
  },
  resolve: {
    modules: [
      path.join(__dirname + 'angular/'),
      "node_modules"
    ],
    extensions: ['.ts', '.js']
  },
  module: {
    rules: [
      {
        test: /\.ts?$/,
        use: ['light-ts-loader', 'angular2-template-loader'],
        exclude: /node_modules/
      },
      {
        test: /\.css$/,
        use: ['to-string-loader', 'style-loader', 'css-loader']
      },
      {
        test: /\.scss$/,
        use: ['to-string-loader', 'css-loader', 'sass-loader']
      },
      {
        test: /\.html$/,
        use: ['html-loader?-minimize']
      },
      {
        test: /\.(png|woff|woff2|eot|ttf|svg)$/,
        use: ['url-loader']
      }
    ]
  },
  plugins: isProd ? [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production')
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: true,
        screw_ie8: true
      }
    }),
    new webpack.optimize.AggressiveMergingPlugin()
  ] : [],
  watchOptions: {
    poll: true
  }
};

module.exports = config;

ユニットテスト設定

こちらもいろんなライブラリを使ってみた結果、Angular のドキュメントでも紹介されていた karma + jasmine に行き着いた。 karma の設定は簡単だったが、disconnected になったときのエラーを探るときが大変。(karma start しないとでてこない)

karma.conf.js

module.exports = function (config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine'],
    files: [
      {pattern: './karma-shims.js', watched: false}
    ],
    exclude: [
    ],
    preprocessors: {
      './karma-shims.js': ['webpack', 'sourcemap'],
      'angular/**/*.spec.ts': ['coverage']
    },
    webpack: require('./webpack.config.js'),
    webpackMiddleware: {
      watchOptions: {
        poll: true
      }
    },
    reporters: ['progress', 'coverage'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['PhantomJS'],
    singleRun: false,
    concurrency: Infinity,

    coverageReporter: {
      dir: 'public/coverage',
      reporters: [
        {
          type: 'json',
          subdir: './',
          file: 'result.json',
        },
        {
          type: 'lcov',
        }
      ]
    }
  })
}

Angular のバージョン上げてみた

Angular 2 -> 4

これ以上早くならないと思っていたビルド時間が早くなり、バンドルのサイズも1〜2割ほどちっちゃくなったので感動。笑

比較結果

Angular 2
<dev>
Time: 15.06s
bundle size: 10.9MB
<prod>
Time: 14.05s
bundle size: 4.72MB
Angular 4
<dev>
Time: 20.40s
bundle size: 9.39MB
<prod>
Time: 11.96s
bundle size: 3.8MB

まとめ

Angular はドキュメントがかなり充実してるので、ドキュメントを見よう!
https://angular.io

※ もう少し細かいところで詰まった気がしているが、だいたい tsconfig.json か webpack.config.js の内容や設定を理解してなかったのが原因だったので設定ファイルのドキュメントを見るのが大事

Ansible local を使ってオリジナルの Vagrantfile を作った

なぜ作ったのか

ホスト OS にいろいろ環境をつっこんでぐちゃぐちゃになるのが嫌だったので、vagrant で作った仮想マシンに全部つっこむようにしていました。ただ、ほぼほぼ vagrantfile いじってなかったので vagrant destroy したりするといろいろインストールやらやり直さないといけません。vagrant の良いところの 1 つとして環境破壊 -> 再構築が簡単であることがあげられると思いますが、再構築の部分をもっと簡単にするためにオリジナルの vagrantfile を作りました。

Vagrantfile

https://github.com/rnitame/Vagrantfile

初めて vagrant up したときか、vagrant provision をしたとき、ゲスト OS にインストールされた ansible が動いて諸々ソフトウェアをインストールします。

f:id:rnitame:20170627164655g:plain

各ソフトウェアのインストールされるバージョンはこの通り。 https://github.com/rnitame/Vagrantfile#software-version

中身について

f:id:rnitame:20170627164826p:plain

hosts の ip に対して playbook.yml にある内容を実行します。内容は roles にある tasks たちになります。 基本やっていることは、apt-get で最新版のものをインストールしてるだけです。他は nginx をスタートさせたりちょっとしたシェルを実行させたり。シェルを実行させるあたりについては、冪等性に気を付けつつ作りました。

はまった

vagrant up したときに ssh のコネクションをするところでタイムアウトしました。いろいろぐぐるタイムアウトになるまでの時間を増やせとかでてきますが解決せず。

解決策

公式の issue にあがってますが、NAT のインターフェースが接続されていなかったのが原因でした。(VirtualBox の Network のところを見て確認) https://github.com/mitchellh/vagrant/issues/7648

なので issue にもあるとおり、以下を vagrantfile へ。

config.vm.provider 'virtualbox' do |vb|
    vb.customize ['modifyvm', :id, '--cableconnected1', 'on']
end

https://github.com/rnitame/Vagrantfile/blob/master/Vagrantfile#L21

まとめ

ansible local を使ってオリジナルの vagrantfile を作りました。ホスト OS に ansible を入れる必要がないので、vagrant up するだけで良いのはとても助かりますね! それと、task 名を記述できるのでどこでなにをしているのかがわかりやすくて良いです。 Docker と組み合わせもしてみたい!