AWSの各種アラートをSlackで受け取る

多分みんなやっているとは思うけど、自分のためにメモ。

AWSの各種アラートをSNSで設定して、とりあえずSNSに自分のメールを追加して、深夜にひとりメールでアラートを受け取ってるみなさん、それSlackでやりましょう。
CloudwatchからSNSに投げているのであれば、Lambda functionをBlue Printからサクッと作るだけでお手軽にSlackに投稿できますよ!(多分)
~~もうメールとかつらいし駆逐していこう~~

実装の全体の流れ

  1. Slackのアラートを流したいチャンネルにIncoming Webhooksを追加
  2. Lambdaに与えるパラメータの暗号化用にKMSで暗号化キーを作る
  3. Lambdaの実行用にRoleを作る
  4. Slack投稿用のLambda functionを作る
  5. おもむろにアラートを上げる。
  6. みんな幸せ(?)

1. Incoming Webhooksを追加

Slackのアラートを流したいチャンネルに、App DirectoryからIncoming WebHooksを追加。
追加した際に出てきたWebhook URLをメモる。

2. KMSで暗号化キーを作る

IAMのKMSのページに行って、後述するLambdaのパラメータの暗号化用にKMSでキーを作ります。
IAMのページはリージョンがグローバルになるので、KMSのページで作るキーはリージョン毎に作りますので、keyを作るリージョンを間違えないように。
キー管理者とキーユーザーはなくても大丈夫です。
作ったキーのARNをメモる。

3. Lambdaの実行用にIAMのRoleを作る

LambdaでKMSのkeyを使って復号化出来るように、IAMで新しいRoleを作ります。
作るRoleにアタッチするポリシーは以下の通り。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt1443036478000",
            "Effect": "Allow",
            "Action": [
                "kms:Decrypt"
            ],
            "Resource": [
                "2でメモったARN"
            ]
        }
    ]
}

4. Lambda functionを作る

Lambdaを作ります。
Blue Printの選択で、’cloudwatch-alarm-to-slack’を選択しましょう。
幸せになります。

環境変数の設定項目で、
slackChannelにSlackのチャンネル名を、
kmsEncryptedHookUrlには暗号化したURLを入れます。

暗号化したURLは次の手順で作ります。
1. Enable Encryption Helpersのチェックボックスをチェック
2. 暗号化キーの選択で、2で作った暗号化キーを選択
3. kmsEncryptedHookUrlのvalueに、1で作ったSlackのWebhookのURLを入れる
4. おもむろに暗号化ボタンを押します。
5. 暗号化されます。

Lambdaのロールはもちろん3で作ったRoleを設定。

5. アラートを上げる

CloudWatchのしきい値を変更してアラートを上げてください。

6. みんな幸せ

市民、あなたは幸せですか?

Read More

iOSアプリ with Swift 第1回 – Swiftの文法編 –

なんかこう、iOSアプリを作ろうとするにあたって、Swift独特の文法というか、書き方だけをまとめたようなのがパッと見つからない気がしたので書いてみた。
他のプログラミング言語をやってきて、Swiftをちょっとやってみよう、とか考えている人はだいたいこの辺を知っておけば良いのではないだろうか。

いや、まぁ、以下に書いたのが全部Swift独特か、って言ったら全然そんなことはないんだけど、Swift特有の安全さ、というのを武器にして書くには以下のことを理解しておくと、Swiftらしいコードが書けるのではないかと。

ちなみに、基本文法は押さえている前提で書いているので、まず基本文法はがあやふやな人は、まずは公式のSwiftのチュートリアルをやったほうが良い。
The Swift Programming Language (Swift 3.1): A Swift Tour

本日のお品書き

Optional

すべての基本。
optionalとはそれがnilになり得る変数、または状態のこと。
nilになり得ない変数、状態のことは、 un-optionalと言う。

すべてのオブジェクトにはoptionalか、un-optionalか、が決まっているし、自分で変数を定義するときは決めなければならない。
un-optionalの変数はoptionalの変数に入れることはできるが、optionalの変数はun-optionalに入れることができない。
Swiftはこの仕組を最大限に活用して、ぬるぽで死ぬ危険性を回避して安全に書くことが出来る。

var hoge: String? = "hoge"
var fuga: String = "fuga"

hoge = nil
fuga = nil // Error

hoge = fuga
fuga = hoge // Error

強制的にoptionalの変数をun-optionalの変数に入れたければ、optionalの変数のあとにつづけて!をつければ良い。
これをoptional変数のunwrapという。
安全にwrapされていたものを強制的に外す(unwrap)イメージ。

fuga = hoge! // unwrap

もし上記のhogeが動作上nilになった場合は、アプリはクラッシュする。
したがって、基本的にunwrapする場合は、明らかにnilになり得ないような場合にのみ限定して使うべき。
それ以外の場合は、後述するようにguard構文を使って回避するべし。

func

なんてことはない。
Swiftにはenum, struct, classなどのオブジェクトを作ることができるが、class以外のオブジェクトにもメソッドを追加することができる。地味に便利。

enum UserRole {
    case user
    case admin
    case owner

    func whichRole(roleNumber: Int) -> UserRole? {
        switch roleNumber {
        case 0:
            return .user
        case 1:
            return .admin
        case 2:
            return .owner
        default:
            return nil
        }
    }
}

struct User {
    let id: Int
    let name: String
    let role: UserRole
    let email: String
    let isPurchased: Bool
    let expired: NSDate

    func isAvailablePurchasedProduct() -> Bool {
        return isPurchased && expired.timeIntervalSinceNow > 0
    }
}

あれ、じゃあstructとclassって同じじゃね、って思うけど、地味にそれぞれできることが違う。
classはオーバーライドできるけど、structはできなかったり。
詳しくは下記。
Swiftのクラスと構造体の使い分けについてのメモ

それぞれの役割を考えて使い分けるべし。

enum & switch – case

enumとswitch – case文のあわせ技。
swiftのswitch – case文はInt以外にもString、enum等にも使うことができる。
特にenumを使ったswitch – case文はSwiftではよく使われる。

enum UserRole {
    case user
    case admin
    case owner

    func getUserRoleNumber() -> Int {
        switch self {
        case UserRole.user:
            return UserRole.user.hashValue
        case UserRole.admin:
            return UserRole.admin.hashValue
        case UserRole.owner:
            return UserRole.owner.hashValue
        }
    }
}

set, get, willSet, didSet

swiftにはどんな変数にもsetter、getterメソッドを簡単に追加することが出来る。

var _fugafuga: String?
var fugafuga: String {
    set(value) {
        _fugafuga = value
    }
    get {
        if _fugafuga == nil {
            return "unknown"
        } else {
            return _fugafuga!
        }
    }
}

さらに便利なことに、willSet、didSetという、変数への代入直前、代入直後のコールバック関数を簡単に追加することが出来る。

var hogehoge: String = "Hogehoge" {
    willSet(newValue){ // 変更後のhoge
        print(hoge)    // 変更前のhoge
    }
    didSet(oldValue) { // 変更前のhoge
        print(hoge)    // 変更後のhoge
    }
}

大変に便利。
特に特定の値の変化に同期してViewにも変更を加えたい時に、didSetをよく使う。
あんまり多用すると処理の順番が追えなくなって泣きを見るので、気をつけるべし。

lazy

lazyを付けたプロパティは、そのプロパティが必要とされるタイミングで値が参照される。

var initialRole = UserRole.admin
class UserManager {
    lazy var currentUserRole = initialRole
}

let manager = UserManager()
initialRole = UserRole.user
print(manager.currentUserRole) // lazyをつけないとadmin、つけるとuserになる

便利そうなんだけど使い所がわからなくて使っていない件。

guard

if文の逆みたいなものだけど、optional変数を扱うSwiftならではの構文。
Swift以外でif文でoptionalを判断する場合、普通は次のように書く。

var optionalValue: Int?
if optionalValue != nil {
    // nilチェック済みの処理
} else {
    throw NSError(domain: "optionalValue is optional", code: 0, userInfo: nil)
}

これをguardを使うと次のようになる。

guard optionalValue != nil else {
    throw NSError(domain: "optionalValue is optional", code: 0, userInfo: nil)
}

// nilチェック済みの処理

if文だとnilチェック済みの処理が一段インデントした箇所に書くことになるが、guard文だとそれがない。
なので複数の値をnilチェックしたい場合、if文だとインデント地獄に陥るが、guardだとそれがない。便利。
ちなみに上記guard文は下記のようにも書ける。というか、下記のように書くことが多い。

guard let _optionalValue = optionalValue else {
    throw NSError(domain: "optionalValue is optional", code: 0, userInfo: nil)
}

// nilチェック済みの処理 : _optionalValueは Int? ではなく、 Int になるので、以降の処理はこれを用いる

これはnilチェックをしつつ_optionalValue変数に入れているので、guard文以降は_optionalValueをIntとして扱って処理をすることが出来る。
optionalValueをわざわざunwrapして処理とかしなくて良い。

また、この書き方は以下のように型チェックにも応用できる。

var anyValue: Any = "hogehoge"
guard let stringValue = anyValue as? String else { // anyValueがStringとして扱えるなら。
    throw NSError(domain: "anyValue is string", code: 0, userInfo: nil)
}

// 以降はstringValueを使って処理をする

とっても便利。

defer

スコープを抜けた時に必ず行う処理を記述することができる。
先のguard文と合わせてよく使われる…ようだ。
便利そうだけど使い所がまだつかめてなくて、個人的にはあまり使っていない。
いや、実際使いそうなんだけど、非同期処理がはさんであるとdefer使えないし…。
とにかく以下の用に使うようだ。

func hogeFunc(hoge: Any) throws -> Bool {
    defer {
        print(hoge) // NSErrorを投げたり、returnする値にかかわらず必ず実行される処理
    }

    guard let _hoge = hoge as? String else {
        throw NSError(domain: "hoge is string", code: 0, userInfo: nil)
    }

    if _hoge == "Hogehoge" {
        return true
    } else {
        return false
    }
}

Generics

まぁ、どこにでもあるジェネリクス型。
これも多用すると元の型がわかんなくなるので注意。

class ObjectCountedList<T> {
    let count: Int
    let list: [T]
    init(count: Int, list: [T]) {
        self.count = count
        self.list = list
    }
}

let user = User(id: 0, name: "hoge", role: UserRole.user, email: "hoge@example.com", isPurchased: true, expired: Date())
let userObjectList = ObjectCountedList(count: 1, list: [user])

let url = URL(string: "https://www.google.co.jp")
let urlObjectList = ObjectCountedList(count: 1, list: [url])

Extension

swiftには既存のオブジェクトを拡張してメソッド等を追加することができるextensionというのがある。
たとえば既存のArrayのオブジェクトに対して、シャッフルするメソッドを追加するには以下のように書く。

extension Array {
    mutating func shuffle() {
        for i in 0..<self.count {
            let j = (self.count - 1) - i
            let k = Int(arc4random_uniform(UInt32(j + 1))) // 0 <= k <= j
            if j != k {
                swap(&self[k], &self[j])
            }
        }
    }
}

余談だが、extensionを使って既存のクラスに便利メソッドを頑張って実装したものの、実際にはすでに似たようなやつが公式で実装されていたことがよくある。かなしい。

Protocol

javaでいうinterfaceみたいなもの。
オブジェクトの振る舞いを予め規定することができる。
後述のDelegateモデルでよく使われる。

protocol HogeProtocol {
    func hoge()
}

class Hoge: HogeProtocol{
    func hoge(){ // HogeProtocolで規定されているhogeメソッドを実装しないとコンパイルエラー
        //何らかの処理
    }
}

Protocol + Extension

protocolにデフォルトの処理を実装することができる。
これを書いておくと、毎回protocolのメソッドを実装しなくてもよくなる。

protocol FugaProtocol {
    func fuga()
}

extension FugaProtocol {
    func fuga(){
        //何らかのデフォルトの処理
    }
}

class Fuga: FugaProtocol {
    // fugaメソッドを実装しなくてもエラーは出ない
}

Delegate(委譲)パターン

Protocol + Extensionの一番良く使う例。
UIKit等の基本的なコンポーネントでよく使われている。
あるオブジェクトAで複数のコールバック関数を設定したい時、予めprotcolで実装したいコールバック関数を規定しておき、そのprotcolを適用したオブジェクトBを実装、オブジェクトBをオブジェクトAのプロパティに追加して、オブジェクトA内の処理内でプロパティに追加されたオブジェクトBのメソッドを実行することで、コールバック処理を実行する方法。
ややこしいのでコードを書くと以下のようになる。

// 予めprotocolで実装したいコールバック関数を規定
protocol ObjectADelegateProtocol {
    func callbackA()
    func callbackB()
}

// ObjectBを追加するプロパティ、delegateを追加。delegateプロパティはObjectADelegateProtocolが適用されているはず。
class ObjectA {
    var delegate: ObjectADelegateProtocol?

    func methodA(){
        // 処理
        delegate?.callbackA() // delegateプロパティはObjectADelegateProtocolが適用されているので、callbackAメソッドがあるはず。
    }

    func methodB(){
        // 処理
        delegate?.callbackB() // delegateプロパティはObjectADelegateProtocolが適用されているので、callbackBメソッドがあるはず。
    }
}

// ObjectBにprotocolを適用
class ObjectB: ObjectADelegateProtocol {
    func callbackA() {
        // コールバック処理A
    }

    func callbackB() {
        // コールバック処理B
    }
}

let objectB = ObjectB()
let objectA = ObjectA()
objectA.delegate = objectB
objectA.methodA() // callbackA()が呼ばれる
objectA.methodB() // callbackB()が呼ばれる

ObjectAの処理の一部をObjectBに委譲しているので、Delegate(委譲)パターン。

こんなややこしいことして何が嬉しいんだよ、って感じだけど、これをやることによってObjectADelegateProtocolが適用されてさえいれば、別にObjectBに限らず他のオブジェクトでも委譲出来る。
これによって特定のオブジェクトへの依存度を減らすことができる。

UIKitは結構このパターンが使われていて、たとえばUITableView、UICollectionView、UITextField、UIPickerView…等、各種基本的なコンポーネントにはだいたい使われているので、覚えておいたほうが良い。

Read More

おんやど恵@湯河原でWanoグループの開発合宿してきた (中編)

では前回に引き続き中編です。

1日目続き

18:30 夕食

みなさん開始から4時間も集中して作業したのでとってもお腹ぺこぺこです。
ご飯を食べます。


見よ、これがWano技術陣だっ!!!!


重鎮の風格漂うWano技術陣の上位3名。


お刺身や…


ちょっとしたアラカルト…


ステーキまである最高のお宿…
それがおんやど恵の底力だっ!!!!
食事中に隣の部屋からカラオケが響くのもご愛嬌

20:00頃 再び開発

夕食が終わったらみんな再び開発に専念。
この時間に温泉に入った人もいるため、ちらほら浴衣姿の人がいますね。
酔っ払って顔が赤い人もいますが、それでも開発を続けるスタイル。
ストイックですね。


何やらセンサーチームはブレッドボードで回路を実装し始めている。


VRチームは相変わらずバーチャルにダイブ中。


飲みながら開発を続けるスタイル。


うまい棒駆動開発。

0:00 ひたすら開発開発開発…

開発が佳境を迎えます。
日付が変わってもとどまることを知らない開発。
みんな徐々に疲れが見えてきました。
だいたいお酒入ってるし。


やられている人1号。


こちらは和気あいあい
とレッドブルとビールとカップラーメンとお菓子。
ジャンキー野郎共ですね。


新しいバーチャルへのダイブを模索するVRチーム。


やられている人2号

そして朝になった。

Read More

try! Swift Tokyoに参加してみた(2日目)

try! Swift Tokyoの2日目です。
1日目のレポートはこちらをどうぞ。

では以下まとめです。


テスト可能なコードを書くということの2つの側面

  • テスト可能なコードを書くのには、Testing OutputとTesting Inputの2つの側面から考える必要がある
  • Testing Output
    • Outputの検証。それが正しいかどうかテストを行って確認をする
    • 大事なのは副作用をコードの境界におくこと
  • Testing input
    • Co-effectが問題
    • Co-effectとは?
      • 依存性の注入
    • Co-effectがある場合のテストが難しい
    • 一つのアプローチとして、グローバルへのアクセスを必ず一つのstructを通して行うことで、環境を制御するやり方
struct Environment {
    let apiService : ServiceProtocol
    let cookieStrorage: HTTPCookieStorageProtocol
    let currentUser: User?
    let dateType: DateProtocol.Type
    let language: Language
    let mainBundle: BundleProtocl
    let reachability: SignalProducer<Reachability, NoError>
    let Scheduler: DateSchedulerProtocol
    let userDefaults: UserDefaultsProtocols
    ...etc
}
    • だいたい24個とかそれぐらいある。
    • たくさんあるけど、環境が制御できるのでやったほうが良い

誰もが知りたいSequenceとCollectionのすべて

  • SwiftのArrayは、Seaquesnce、Collection、BidirectionalCollectionというProtocolをベースに作られており、それによってSwiftの堅牢さが保たれている
  • Sequence Protocol
    • 要素のリスト
    • 無限に追加できる
    • 1回だけのiterate
    • Iteratorと、IteratorProtoclに適合したプロパティをもつ
      • IteratorProtocolとは、Elementとnextというメソッドをもつprotocol
    • Sequenceにcountというメソッドを追加してみる
let number = users.filter({$0.isAdmin}).count // => fine 一度countしてから捨てるので、処理が二重で行われてオーバーヘッドがある
let number = users.count({$0.isAdmin}) // => great 本当はこうしたい
    • 次のように拡張すると便利
extension Sequence {
    func count(_ shouldCount: (Iterator.Element) -> Bool) -> Int{
        var count = 0
        for element in self {
            if shouldount(element){
                count += 1
            }
        }
        return count
    }
}
    • もう一つEach Pairという拡張がオススメ
      • [A, B, C, D]のリストがあったとき、AB, BC, CDというペアを作って比較したいときがある。
      • これをつぎのようなメソッドを追加することで実現する
extension Sequence where Self.SubSequence: Sequence, Self.SubSequence.Iterator.Element == Self.Iterator.Element{
    func eachPair() -> AnySequence<(Iterator.Element, Iterator.Element)> {
        return AnySequence(zip(self, self.dropFirst()))
        }
    }
}
  • Collectionというprotocol
    • Sequenceベースのprotocol
    • すべてのCollectionは有限
    • 複数回Iterateできる
    • index, startIndex、endIndex, subscriptionメソッド, indexメソッドを持つ
    • APIErrorCollectionはfileprivateで自分で制御できない、自分でextensionで追加すると便利
  • BidirectionalCollectionというprotocol
    • Collectionベース
    • beforeというメソッドがあり、前にも後ろにも戻れる
  • 他にもMutableColelction、RandomeAccessCollection、RangeReplaceableColelctionなどがある

様々な場面でSwiftを使う

  • Swiftのオープンソース化にともなって、ウェブサービス、API、マイクロサービス、それ以外に、デーモン、ユーティリティ、ツールも作れるようになった
  • Swiftを使う理由としては、型安全、protocol、パフォーマンスの良さ等があるので、他言語と比較してSwiftを選択するというのもありだと考えた
  • SwiftはCと同じLLVM基盤なので、C言語のライブラリをimportして読むことが出来る
  • 事例1 – クローリングサービス
    • ウェブクローリングサービスをSwiftで書き直し始めている
      • もともとはpythonで書いていたが、他言語との将来性を考えた結果、Swiftにした
      • クローラー、DB(mysql)、APIサーバーの3つの構成
      • API経由でクローラーを制御するようにした
        • APIは型があるgRPCプロトコルベースでおこなっている
    • クローリングに必要なものは、すべて既存のC言語ライブラリのimportで実現できる
    • 今のところ20日程度動かし続けているけど問題は起こっていない
  • 事例2 – センサーを動かす
    • Swift for ARMというライブラリを使ってラズパイを動かす
    • I2C Bus経由で圧力センサーにアクセスして、slackにpostする
    • I2CBUSへのアクセスは、includeしてfopen, ioctlシステムコールを使えばいける
      • https://github.com/novi/i2c-swift にあげた
  • 作り方
    • すでにC言語のライブラリがあればそれを使えばいい
    • 他の言語のライブラリも、Swiftへのポートをすることで使える
  • Tokyo-Server Side Swift Meetupというのをやっているよ!
  • バッチ処理、APIサービス、コマンドラインツール、社内ツール等に使ってみると良い
  • スクリプト言語のようにつかうこともできる
  • (質問)クローラーをswiftに切り替えて、パフォーマンスは具体的にどう上がったのか
    • まだあまり測定できていないが、使っていたライブラリのオーバーヘッドがあったので、それを使わなくなくなったのは大きい
  • (質問)NSURLSessionを使わずに、libcurlを使っている理由はなぜなのか
    • Foundationはlinuxでほぼ実装はできているので、NSURLSessionも使えるが、NSURLSessionはHTTPの仕様に近い部分がさわれないので、libcurlにした
  • (質問)ラズパイとかにFoundationをのっけてるわけではないよね?
    • ラズパイはSwiftをサポートしているlinuxがのるので動く
    • ArduinoはOSがないので動かない

VRの革新と新たなユーザー体験(LT)

  • VRをどのようにゲーム、エンターテインメント以外に使えるかを検討している
  • ティム・クックはARはとても魅力的だと話している
  • Retail業界
    • アリババはバーチャルショッピングに対応
      • 誰でもニューヨークの店舗で買い物が出来るようにした
  • 不動産業界
    • ラトビアの不動産会社が、物件の360度動画を取って、それをVRで体験することが出来る
  • 自動車業界
    • Volvo、Audi、ジャガー、ホンダ、フォルクスワーゲン等が、VRによるバーチャルショールームとテストドライブを提供していたりする
  • ニュースやメディア業界
    • New York Times等が、360動画による放送をしたりしている
  • スポーツ
    • 東工大が開発したVRスケートボードがある
  • MobileBusinessInsight.com、VR Hub Tokyo Meetupを見てください。

iOSにおけるDocument IndexingとApp Search

  • App Searchとは?
    • Spotlight、Safariにアプリ内コンテンツのサジェスト/検索ができるシステム
  • App Searchはそんなに使っている人は少ないがすばらしい機能なので是非使って欲しい
  • Core spotlight API
    • 特徴
      • インデックス化をする処理を書く
      • これはローカルユーザーだけが見れる
      • 大量のアイテムのインデックス化に向いている
    • 作り方
      • Core spotlightをimportしてインデックス化する
    • 重要な属性
      • expirationDate – expireが設定できる
      • domainIdentifierを使えば複数のアイテムをまとめてインデックスすることも出来る
    • iOS10からは、spotlightからアプリの検索ができるようになる
  • webマークアップ
    • 対応するウェブサイトがある場合に使うと良い
    • ウェブサイトにディープリンクを追加
    • markupを使ってリッチ情報を提供する
    • ユニバーサルリンクか、スマートバナーを追加
    • safariで検索した時に、アプリにリダイレクトされるようになる
  • 詳しくは、gridNAのgithubを見てください
  • (質問)imageをインデックスに載せるにはどうしたらよいのか。リモートからダウンロードするけど、保存する処理を書いたりする必要があるのか。
    • URLでインデックスに追加することが出来る
    • 自動でシステムが縮小してくれる
  • (質問)Spotlightはどれぐらいのユーザーが使っているのか
    • 自分たちのアプリでは、50%ぐらいの人がSpotlightから来ている
  • (質問)データはindexに載せたかどうか確認する方法はあるのか
    • インデックスされたかどうか確認する方法はある

スタートアップのSwift

  • 2016年にアプリを開発した
  • 女性の友情を育むアプリMVP
  • PARSE + SWIFTで開発したら早く開発ができた
  • いくつかのメディアからインタビューを受けた結果、最初の2週間で10万人が集まってしまった
  • あまりにも多くのユーザーが一度に入ってしまったので、幾つかの問題が出てきた
    • 1分あたりのリクエスト数がParseの制限を超えてしまった
      • 一部のlocationのユーザーしか使えないようにして、なんとかリクエスト数を絞り込んだ
    • リテラシーが低いユーザーがどんどん使い始めた想定していないバグが露見した
      • slackチャンネルと繋いで、テストユーザーを募集してテストをしてもらった
      • 再現できないクラッシュに対しては、Slackでコアユーザーに呼びかけて会議に出てもらったりした
  • Swiftの機能を使って安全に書く方法を覚える必要があった
    • 新しいことを覚えたら、コードをどんどん修正していかなければならない
    • そのうちはじめに書いたコードは全部捨てないといけなくある
  • また、Parseがサービスを閉じることになった
    • マイグレーションをしなければならない
    • Parseに依存していたので、APiクラスでラップしていなくて、新しく全部別のサービスに載せ替えなければならなかった
  • swiftの言語のバージョンの変更に対応するのも大変だった
  • ただし、swiftは開発し易い言語だし、改善しやすい言語であるので、結果、大事なことに集中できると思う

きちんと型付けされたメッセージ

  • 可読性の重要さ
  • 複雑性を制御する方法を学ぶ
  • 複雑性は我々のロジックから来ているものと、我々がコントロール出来るものがある
  • 具体的に可読性が高いコードを書くということは?
  • 設計
    • e-mailをユーザー名とドメインに分ける処理
    • func split(email: String) -> (String, String)?
    • 可読性をあげるレベル1 – コメントを書く
      • コンパイルに影響を及ぼさないので、それを理解するかどうかはエンジニア次第
    • リーダビリティレベル2
      • typearliasや、structでSplitEmailというオブジェクトを定義する
      • それぞれ代償がある
        • 認識のコストは下がるが、オーバーヘッドや煩雑さが増える
    • リーダビリティレベル3
      • 返り値がoptionalであるということ
      • 次のようなwrapperを使ってステートを管理する
enum SplitEmail {
    case valid
    case infalid

    func init {
        if hoge {
            self = .valid
        } else {
            self = .invalid
        }
    }
}
      • これによりSplitEmailには2つの状態があることが理解できる
    • リーダビリティレベル4
      • splitterを定義する
      • Split<String, EmailSplitter>
  • 2つめの世界 – Delegation
    • Appleの定義するdelegateはoptionalである
    • これはライブラリのスタンダードな使い方
    • しかし自分たちはそうしたくない
  • Appleの仕様どおりではない場合、むしろ理解を妨げてしまうかもしれない
    • 複雑性、監修、モデリングのコスト…etc
  • 可読性を高める最短のルートはGodモード。つまり人の身になって考えるということ

忙しい人のためのApp Transport Security(LT)

  • 安全なhttpsと安全でないhttpsがある
  • 暗号化の方式によってはhttpsであっても安全でないと判定される
  • 詳しくはAppleのドキュメントである、Information Property Listをみるとよい
  • nscurlコマンドでもATS対応しているか確認をすることができる
  • ATSの無効化はいくつは種類がある
    • 全無効化
    • ATSの特定のドメインのみ無効化
    • iOS10から追加された項目
      • AVFoundationの通信に関して無効化
      • WebViewの通信に関して無効化
      • ローカルホストに対する無効化
  • WebView無効化を試した
    • HTTPの通信、安全なHTTPSの通信は出来るが、安全でないHTTPSの通信ができない
    • iOS10.2では、UIWebViewは通信できるという事実(WKWebViewはできない)

Swiftで堅牢なカラーシステムを構築する

  • カラーシステムのアーキテクチャー設計を1から作った
  • カラーシステム構築による便利さ
    • カラー設定を一箇所でできる
    • プラットフォームで一貫したカラーパレットを提供できる
    • 適用が楽になる
  • Appleのヒューマンインタフェースガイドラインは改訂を何度もしている
    • Dark modeの追加等
  • 色の選択はUXにかなり影響する
  • デザインはInterface Builderで決定するか、プログラマティックにするかという問題
  • Interface Builderはパワフルになってる
    • .clrファイルを共有すれば、カラーパレットの共有も可能
  • Interface Builderは共通のリファレンスがない
    • .clrファイルを共有しても、すべてのintereface builderを設定するのは大変
    • 複数のテーマでviewをカスタム化することができない
  • プログラマティックにおこなう
    • すべてのUIエレメントを一気に更新することができる
    • 影響範囲は一つのファイルのみ
    • カスタムカラーを作成できる
    • Zeplinというカラーエキスパートツールはこの処理をシンプルに行える
extension  UIColor {
    struct Pallet {
        static let hogehogeBlue = UIColor(...)
        static let white = UIColor(...)
        static let black = UIColor(...)
        ...
    }
    class var hogeText: UIColor {
        return Pallet.black
    }
}
  • 色を反転した時に、強調の加減が同じになるかどうかなどをチェックしたほうが良い
  • ユーザーのアクションによって全体の色を変更したい場合
    • Notification Centerを使って複数のViewを一度に変える
    • 次のように実装すると良い
protocol ColorUpdatable {
    var theme: Theme{get set}
    func updateColors(for theme: Theme)
}

protocol ColorChangeObserving {
    func addDidChangeColorThemeObserver(notificationCenter: NotificationCenter)
    func removeDidCngeColorThemeObserver(notificationCenter: NotificationCenter)
    func didChangeColorTheme(notification: Notification)
}

private extension ColorThemeObserving {
    func theme(from notification: Notification) -> Theme? {
        ...
        return theme
    }

    func updateColors(from notification: Notification){
            ...
    }
}

extension UIviewController: ColorThemeObserving {
    @obj func didChangeColorTheme()...
}
  • Inclusive Design
    • 男性の8%、女性の0.4%が色覚障害を抱えている
    • iOS10は色覚障害向けフィルターが設定できる
    • Inclusive Colorというライブラリを使うと良い
    • Inclusive Designの戦略
      • モノクロではなく色を使うと強調することが出来る
      • 大きなテキストは高いコントラスト比をもつのがよい
      • 色ではなく、コントラスト比に注目するということ
    • 昨年のWWDCのInclusive Design Sessionを参考にするとよい

サーバサイドSwiftの実例(LT)

  • Vaporを使っている
  • 開発は、linux固有のバグに悩まされたくなかったこともあり、xcodeで行っている
  • vaportのテンプレートを用意した
  • 実演したように、簡単にサーバーサイドSwiftは実現できる

モックオブジェクトをより便利にする

  • Interaction Test
  • protocolを定義することで、fake objectとreal objctの両方が使える
  • モックオブジェクトにverfyメソッドを追加すると、複数のassertionを一気にできる
  • default valueで#file、#lineを追加してロギングすることで、エラー時のコードの位置がわかりやすくなる
  • 大事なものに反応して、大事でもないものは反応しないようにするというテクニック
    • 大事でないものについては、マッチメソッドを外部から追加することで対応する
  • Hamcrest Matchers – 様々な言語で採用されているマッチャー
  • greaterThanOrEqualTo(2)、anything()というマッチャー
  • fakeオブジェクトを作る理由
    • リソースをつかうとき、グローバルへの影響が大きい時…
  • qualitycoding.org/tryswift2017 にサンプルコード等があるので参考にしてください

チームの生産性を改善するために決断疲れを最小化する

  • ソフトウェアエンジニアは常に意思決定をしているため、決断疲れが起きる
  • 特に何もしないと個々で判断をするので、それぞれで決断疲れを起こしてしまう
  • 意思決定の流れをシンプルにすることで問題を解決する必要がある
  • (問題)Xcodeのどこにファイルの置き方
    • ファイルを探すのに意外に時間がかかっているという事実
    • 色んなアプローチがあるが、シンプルにapplication, components, UIに分けた
    • Application
      • アプリ自体に関する情報
      • info.plistとかassetとか、launchscreenとか
    • components
      • 各コンポーネント毎にまとめた
    • UI
      • 各View毎、ViewController毎にまとめる
  • ペアプロをやっている
    • ほとんどがペアプロ
    • 2人が同じコードを見れるように、一つのiMacに2つのディスプレイと2つのキーボードを追加
    • Ping-Pongプログラミング – 順番にプログラミングしていく
    • Driver-Navigatorプログラミング – 経験があるほうがナビゲートしていく
  • (問題)プロパティ、メソッドの一覧性
    • Swiftの // MARK:- を使う
    • これを自動入力するためにXCodeのテンプレートを作る
    • protocol conformance – extensionでprotocolに適合するメソッドを分けるということ
  • Cross-Functionalペアリング
    • エンジニア-デザインのペアリング等の複数の職種間でのペアリング
    • ボタンをどう定義するかの話し合いとかを行う
  • (問題)UIオブジェクトのデザイン
    • 次のようにしてスタイリングを予め定義しておく
enum UIButtonStyle {
    case primary, nagative
    func applyTo(button: UIButton {)
    case .primary:
        ...
        return  cutomButtom
    case .negative
        ...
        return  cutomButtom
    }
}
  • Retrospective(振り返り)
    • コアチームメンバーだけで行う
    • 食事やお酒を出したりする
    • ホワイトボードをKeep, Discuss, Improveに分けてタスクを分ける
    • ファシリテーターは最後の締めくくりをポジティブになるようにする
  • 決断は一人で行わせるのではなく、チームでブレストすることで行う
  • (質問)ペアプロという二人で働くことにより損なわれる快適さについてどうか
    • 確かに人との関係に集中しないといけない
    • ただ、自分ではやっていないことを学ぶ機会ではある
    • 自分の好みを犠牲にして、もっと良いものを見つけることができる。また、他の人に自分の好きなものを進めることが出来る
  • (質問)リモートで働いているとペアプロが難しいがどうしたらよいか
    • 人によってはスカイプを使ってペアプロをしたりしている
    • 自分の経験から、リモートでもスカイプなどでペアプロすることで寂しさがなくなって良かった
  • (質問) 奇数の開発者がいた場合どうやってペアプロしたら良いか
    • DoITというツールを使う
    • 一人の人がでるようなら、頻繁にペアを変えるようにする
    • 一人の時には小さな仕事をやってもらうようにする

Client-Side Deep Learning(LT)

  • Metal Performance Shaderに追加されたCNN (convolutional neural network) APIs – MPSCNNというのがある
  • 今まではiPhoneからAPI経由でサーバーに送る必要があったが、今はこのMPSCNNを使うことでローカルで行うことが出来る
  • 学習は強力な計算力を持つPCでやって、iOSに学習した結果をもたせて処理を行うという仕組み
  • MPSCNNはいろんなファイルフォーマットに対応している

オープンソースコミュニティをスケールさせる

  • オープンソースの流れ
    • ソースコードを公開する
    • ユーザーが使い始める
    • ソリューションになる
    • どんどんスケールする
  • プロジェクトが大きくなるとどうなるか
    • プロジェクトの勢いを保つということが難しくなる
      • アクティブユーザーが増えるとユーザーサポートに時間がかかってしまう
      • なんらかの方法で機能追加を検討するプロセスが必要
      • 他のことに時間を大きく取られて、メインテナー自身が一番のユーザーでなくなってしまうという事実
    • ユーザーとの情報のアンバランスがおきる
      • ユーザーはissueを投げたら覚えているけどメインテナーは覚えていないという問題
  • どうしたら良いか
    • エラーメッセージの改善
      • 余計なエラーメッセージを表示することをやめて、重要なメッセージは色をつけるようにした
      • 余分なエラーメッセージを表示するオプションをつけた
      • エラーが発生した時点で関連するものを提示する
        • issueへのリンクを貼るとか
    • issue botを使う
      • ボットを使うことで、オープンイシューとプルリクが大きく減った
    • issueテンプレートを導入した
      • ほとんどの人が守ってないけど
    • コマンド1つでユーザーの環境変数を収集して、バグ報告に役立てられるようにする
      • 適切なタイミングでボットによってコマンドを提示するようにする
    • 似たようなissueが沢山上がるような場合はドキュメントを充実させる必要がある
      • 適切な箇所にリンクを貼る必要がある
      • これも関連するissueが投げられたときは、botが自動でリンクを提示するようにする
    • ボットを使うことでissueの一貫性を保つ
      • しばらく投稿がないとissueを自動でクローズする
      • これによってissueのライフサイクルを保つことができる
    • Dangerというサービスをつかうことで、プルリクされたら自動テストをまわして、テストに失敗したらユーザーにテストを改善するように通知するようにする
    • コントリビューターを増やす
      • コントリビューターを増やすためにもコード規範を作る
      • 全員が検証できるように透明性を保つ
      • コードベースのシンプルさを保つ
      • いつでもフレンドリーに受け入れる体制にする
    • ユーザーがソフトを拡大できるようにする
      • DSLを利用できるようにすることでユーザー自身である程度制御できるようにする
      • プラグインとして追加できるようにしても良い
  • (質問)ライブラリでメンテナンスできていないものはあるか。それをどうするか
    • 透明性を確保することで、誰かに引き継ぐ

Swiftでのエラーハンドリングとエラー耐性についての教訓

  • ここではError型の話ではなく、コードの中で理想的なコードパスではないものすべてをエラーと呼ぶことにする
  • エラーハンドリングにおけるinputについて話す
    • 明示的入力 – 引数、self等
    • 暗黙の入力 – 状態
  • 状態
    • グローバル変数とシングルトン
    • 時間的状態
      • コードを実行する順番とか
      • コメントや、間違った順番でコンパイルできないようにするとか
    • リアル世界の状態
      • ファイルシステムやネットワーク、以前のコードの実行出力等
    • これらの状態の変更は無計画にやるべきではない
  • ハンドリング方法
    • 特定の状態を表すインスタンスを作る
    • init時に、特定の状態の型を入れるようにする
  • optionalを使う時
    • あまり大きなエラーではないとき
    • 発生頻度がやや起こりがちなエラー
  • Error型を使うとき
    • 致命的な問題に使われるとき
    • 発生率が低く、影響範囲が広いエラーに利用するのが適切
  • 入出力の流れを意識してあらゆる状態に対処する
  • (質問)fatalerrorを使うときはどういうときか?
    • 確かに”!”を使うことはあるが、そういう箇所の確認はテストを回して確認することにしている
    • また、なぜそれをやらなければならないかをちゃんと探る

ゲーム&ウオッチ

  • 人は昔から時計でゲームをやってきた(任天堂のゲーム&ウォッチの写真を見せながら)
  • SpriteKitでゲームを開発できるようになった
    Apple WatchでNESエミュレータが動作する様子。
  • C++のNESエミュレータでやってみた
    • ウォッチでは低レイヤーの描画が使えない
    • フレームごとにテクスチャーを生成して対処
    • サウンドはAVFoundationが使えるようになったのでそれで行った
      • ただしシミュレータでは動作しなかった
  • 多くのセンサーが利用できそう
  • タッチイベントが、Touch Up取得できないという事実
    • LongPressイベントの時間をめちゃくちゃ短くして対応
  • Watchはマルチタッチイベントに対応していないため、デジタルクラウンでBダッシュを実現
  • Carthageに対応したので、誰でも簡単にApple Watchアプリに組み込むことができるよ!!

なぜ登るのか

  • オススメする理由1
    • チームスポーツはメンバーのレベルがみんな同じでないと面白くない
    • ボルダリングは違う
    • 同じ壁で複数のレベルが楽しめる
  • オススメする理由2
    • 登るのには色んなアプローチがある
      • 体のやわらかさでいくか、筋肉量にものをいわせていくか、ジャンプ力でいくか、バランス感覚でいくか…など
    • これらの要素をミックスさせて、自分だけの解決法を考えられる
  • オススメする理由3
    • 一人でできるスポーツ
    • でもグループで競争でやっても面白い
  • これ、Swiftと同じではないか?
  • みんなボルダリングをやるといいよ
  • (質問)東京周りで、今この時期はどこにボルダリングがオススメか。
    • インドアのボルダリングが良い
    • 新宿のレックスジムにはフローティングルーフがあり、これがとても面白い

Read More

try! Swift Tokyoに参加してみた(1日目)

try! Swift Tokyoに参加してきました。

カンファレンスのネームプレート。try! Swift Birdちゃんが可愛い。
Twitterで名前を募集している。

カンファレンスの様子

僕はしばらく大きなカンファレンスに出ていなかったのですが、アプリも作ってるし、Swiftのイベントがこの時期にあることを知って参加することにしました。

参加してざっくり感じたこと。

  • 参加者は結構多い。
  • 同時に複数の場所で講演をやることはないので、見たい講演は必ず見れる。
  • 同時通訳の精度がすごい。
  • 朝ごはんと昼ごはんが出るよ!
  • 講演の大半が英語なので、ある程度英語ができるともっと楽しいと思う。(自分はできない)

こんな感じです。
他の言語のカンファレンスと比較して、参加料が高くしかも英語がメインな感じなので、ちょっと敷居は高いのですが、それだけの価値は十分にあると感じました。
特に同時通訳の精度が高く、専門用語も適切に翻訳できてて非常に聞きやすかったです。
…同時通訳レシーバーがあることを最初知らず、最初の2講演を詳しく理解できなかったのが悔やまれるところ。

以下、1日目のまとめ。


Swift開発者が知りたかったけど聞きにくい機械学習のすべて

  • 機械学習とは、男の場合の平均値、女の場合の平均値、体重がこれぐらいの人の平均値、こういう職業の人の平均値…etc等、属性ごとに平均値を出すみたいなもの。
  • 機械学習はUIデザインに似て、ちゃんんと動くか、それが正しいのか証明できないのが難しいところ。
  • 機械学習は、TensorFlowのチュートリアルや、ドキュメント、本が揃っている
  • python on the server, Swift in the hand

Swift on Android

  • C言語はすべてのプラットフォームで動く。なのでC言語にしちゃえばよくない?
  • Android NDK (native development kit)というAndroidをC言語で書くSDKがある。
    • AndroidはOSがなかなか統一されないので、Cの標準ライブラリも微妙に違っててやりづらい
    • Hell Problemだぜ!
  • Blurrr SDKというのを作った
    • Macアプリとか、Windowsアプリとかも動くぜ!

SwiftのPointy Bits

  • Swiftって安全な言語だよね。
  • でも安全じゃなく書けるよ。
    • unsafePointerを使おう
  • Unsafe Pointerは次の利点がある。
    • C言語のAPIが使える
    • 速度が速い
      • ただし安全性とのトレードオフはあるので注意。

アプリを新次元に導く3D Touch

  • Appleは3Dタッチに5年もの開発を費やしたんだからみんな使おうよ!
  • 3Dタッチを使う理由
    • ユーザーのショートカット
    • App Storeで3Dタッチ対応アプリのところに出せる
  • 3Dタッチでできること
    • ホーム画面のクイックアクション
    • Peek & Pop – 事前にページを開く前にプレビューをする等によく使われている
    • Notification Content Extension
      • 通知画面にアクションを追加できる
  • 3Dタッチは古い端末に対応していないので、長押しなどのアクションを代用して、同じ機能を古い端末で対応するようにしたほうが良い

Pixcels、プロセスと情熱

  • 主に開発おモチベーションをどう保つかという話
  • 講演者は去年あたりから、Blogを始めたり、様々なハッカソンに参加したりして精力的に活動してきたらしい
  • (あまり興味がなかったのでちゃんと聞いてない…)

毎日リアクティブ

  • シナリオ駆動にすることでステートを減らすというアプローチ
  • Swiftでリアクティブをやる方法
    • RXSwift
    • ReactiveSwift
    • etc…
  • 既存のどのような処理に適用していくか
    • MVVMモデル
    • async operation
  • observerパターンに適用するのがよくある
  • トレードオフ
    • デバッグがやりづらい
      • ログイベントを一連のストリームで発火させることでデバッグをやりやすくする
    • フランクにやりすぎるオーバーヘッドが大きくて死にやすい
    • 変更時の影響範囲のわかりにくさ
    • 多用するとカオスになりがち
  • 大事なのは、必要な箇所だけを使うということ

Unsafe Swiftの安全性(LT)

  • Unsafeで扱いたいことがある
    • C言語で書きたい
    • 速度をあげた
    • Lowレベルにアクセスしたい
  • https://www.raywenderlich.comでUnsafe Swiftについて書いた
  • ちゃんとした書き方をすれば、Unsafe Swiftでも安全性を担保することはできる、らしい…。

クックパッドアプリのテストを味わう

  • UITestにフォーカスした話
  • Cookpadアプリ
    • グローバルアプリと日本アプリの2つがある。統合はまだしていない
    • UIコンポーネントは複数大きく変えている
    • だいたい10万行ぐらいある
    • 以前は2週間、最近は1ヶ月毎にアップデートしている
  • kano-model という品質モデルがある
    • Attractive – Must-be Qualityの2つのパラメータ
    • Diachronic Quality for mobile
  • UITestのやり方
    • テストを書いてからリファクタリングをする
  • UITestの実際
    • マニュアルテストは簡単に出来る、ユニットテストはめんどくさい
    • でも理想はその逆
    • Cookpadでは2015年〜2017年にかけてUITestを初めてCrash率を下げ続けた
  • UITestの書き方
    • シナリオを書く
    • シナリオをRubyコードに変換
    • Appiumで実行
  • Appium
    • XPATHはOSのフレームワークにかなり依存している
    • テストをUIレベルからメソッドレベルに移動することが大事
  • image diffを見せるようにした。
  • 数ヶ月前にSwiftを実装し始めた
    • テストがあるので安心してSwiftの実装出来る
  • テストの自動化は、エンジニアのスキルとはまた違ったスキルセットが必要
  • (質問)Appium使ったことあるけどめっちゃ時間かかるんだけどどうしてAppiumなのか?
    • システムアラートを制御することができる
    • 外部の環境をいじれるのでこれを選択している
    • コミット毎にテストを回しているわけではない
  • (質問)時間がかかるboundaryのテストの代替テストはどういうものを考えたか
    • よくある文字入力などのバリデーションにかかわるテストは、UIテストではやらず、ユニットテストで担保する

データレイヤを分離する

  • MVAモデル(Mininmum Viable Architecture)という考え方
    • 必要最小限のアーキテクチャー
  • CoreDataやRealmObjectはスレッドを意識したりしないといけないけど、Viewレイヤーでそれを意識したくはない。
  • DTOモデルに変換するというアプローチ
  • Plain old swift Object(POSO)で書く
  • CoreDataやRealmObjectからDTOモデルに変換する
  • デメリット
    • 自分たちでモデルを管理しないといけない
    • 変換処理を書く必要がある
  • (質問)DTOに変換するのはオーバーヘッドがあるわけだけど、その線引きをどうするか
    • チームの規模が大きかったら、全員が全員スレッドとかを考えなきゃいけないとめんどくさいので、そういう視点で線引をどうするか考える

UIをSwiftlyに書く

  • Resultライブラリを使う
    • API読み込み時に、成功時のパターン、失敗時のパターン、失敗したけどデータを受信したパターン、通信は成功したけどデータが不正のパターン…等色々考えると大変
    • Resultライブラリを使って、成功/失敗に応じて処理を分ければ2つ考えるだけでよい
  • AutoLayout
    • storyboard、xibではIDベースでコンポーネントが管理されている
    • プログラマティックにAutoLayoutを実現するのは大変
    • Autolayoutを書くとよくわからない
    • Cartograpyというライブラリを使う
      • Autolayoutをわかりやすいコードに書けるラッパーライブラリ
  • ステート管理
    • APIはロード中/成功/失敗3つの主要なステートがある
    • コレをboolで扱う
      • このパターンはisError && isLoadingのステータスの場合がよくわからなくなる
    • enumとswitchステートメントで管理すれば良い
  • コード共通化
    • ProtocolとProtocol extensionを利用する

SwiftのWeb APIとアプリをともに構築する

  • API設計
    • Paginationの例
      • Get /posts?page=2
        • 各ページでのpostコンポーネントの担保
      • Get /posts?before=2
        • このようにすることで、ID 2のページの前のページの要求をすることができる
    • APIのバージョニング
      • /v1/posts
    • REST
    • APIの問題点
      • クライアントのアップデートが必要
        • Web Linking RFC5988を使うというアプローチ
        • SwiftではWebLinking.swiftというライブラリがある
        • application/hal+json, application/vnd.siren+jsonという方式で書くと、APIのアップデートに耐えうる実装にできる
        • さらにHypermedia APIを使うことで、ビジネスロジックをバックエンドに持ってくるができる
  • APIを実装する上で使えるSwiftのウェブフレームワーク
    • 主にfrank, kitura, vaporの3つが有名
    • frankは軽量なフレームワーク
  • テスト
    • linuxでXCTestを使える
  • デプロイ
    • herokuが楽
    • IBMのブルーミックスというのもある
    • 他にもDockerを使ったり、もちろんマニュアルデプロイでも良い
  • ロギング
    • paperteailを使ってプリントしたエラーを取得する等

楽しく便利なSwiftチャットボット

  • 去年は色んなチャットボットサービスが出て来た
  • まだまだ微妙な感じ
  • LINEで言語学習ボットを作ってみた
  • グーグル翻訳のAPIを使う
  • ボット上で言語登録ができる
  • Spaced Reptirionで言葉を覚えたか確認する
  • ボットの作り方
    • 制限のあるインタラクション
      • テキストとかスタンプとか画像とか動画とか、全部に対応しようとしない
    • とにかくシンプルにする
    • 他のサービスのapiを活用する
    • 不必要にユーザーを長く拘束しないようにする
  • (質問)VRにボットを拡張する可能性はあるのか
    • 今すぐではないが、VRが軌道に乗れば、確実にくると考えている

Realmを使ってコラボレーションアプリを作る

  • コラボレーションアプリとは?
    • Google Docs/Slack/JIRA等の複数のユーザーが同時進行で作業をすることができるアプリ
  • Realmとは?
    • 大事なのはDBマッパーではない
    • データーベースそのもの
    • schemalessではない
  • Realmの利点
    • オブジェクト思考で書ける
    • クラスを実装するように書けるので、新しいことを覚えなくてよい
    • React NariveやXamarinにも対応しているので、クロスプラットフォーム
    • すべての環境で同じデータを使いまわせるので、バックアップがとれる
    • トランザクション管理をしているので、リアルタイムの共同編集ができる
    • サーバー、モバイルの両方でRealmを採用すれば、アプリからjsonを排除することが可能
  • Realmの通知機能
    • プロパティの変更、オブジェクトの変更、コレクションの変更、ファイルの変更など、様々な変更に対して通知を行える
    • イベントハンドリング
  • アクセス権の管理
    • Admin Realm, Management Realm, Permission Realmなどの特別なRealmを使えば、アクセス権の管理が可能
  • (質問)RealmをPHPから操作する等、さらに多言語対応をしていく予定はあるか
    • 今のところPHPの予定はないが、いくつかの言語をサポートする予定はあり、そこになくてもGithubで要望を上げてくれれば検討する

独自のツールを構築する

  • ネイティブアプリの問題点
    • ネイティブアプリのテストが長くなってしまう問題
    • ウェブアプリケーションも提供していたが、カスタムUIがたくさんあるとウェブ側の開発のスピードについていけない
  • これらの問題は、コードの再利用が出来ていないことによるのではと考えた
  • 独自コンポーネントのインフラの構築のアプローチ
    • jsonベースのコンポーネント
    • React in swift – Katana
    • React Native
  • すべての実装を、Swiftにするか、Javascript(React Native)にするかすれば、コードが使いまわせるのでは。
    • Swift
      • メリット – 盛り上がっているし非常にエキサイティング
      • デメリット – コンパイルは遅い、独自実装が沢山必要
    • React Native
      • デメリット – 依存性が593もある、まだ若い、アップデートが早い
      • メリット – ただしAPI思考アプリと親和性が高い
  • その他のReact Nativeのメリット
    • シンプルなレイアウトシステム
    • テスト界隈は進んでいる(javascriptなので)
    • コミュニティはオープン
  • React Nativeでコンポーネント化することで、コードを再利用をはかった。
  • (質問)複雑なコンポーネントをReact Nativeだけでできるのか
    • 今のところ自分達のアプリでは、問題になっていない

リアルタイム物体検出アプリでよりよいフィードバックを提供する(LT)

  • Wantedlyで行っている名刺の検出の例
  • 前提
    • カードの認識はできていて、位置が定まっているという前提
  • 複数のオブジェクトがカメラに写っている時に、各フレーム間のオブジェクトラッキングが問題
    • オープンCVの標準のトラッキングを実装したけど、一部の端末で微妙だった
    • なので独自トラッキングメソッド実装した
  • その他iOSアプリでは、CoreImageを使ったトラッキングがあるが、あくまで顔認識に特化したもの
    • サンプルコードをGithubにあげた

UXエンジニアという働き方

  • エンジニアもUXを考える必要があるということ
  • エンジニアにしかできない提案がある
  • UXを良くするためにやっていること
    • リテラシーが高くなく、アプリに馴染みがないユーザーをターゲットにした場合
    • 実際にユーザーにプロトタイプをいじってもらって検証した
  • デザイン思考の学習
    • デザイナーの思考法であり、これによりイノベーションを起こすような思考法
    • ユーザーへの共感がポイントらしい

以上、本日はこんな感じでした。

今日の講演の内容を振り返ると、全体的に

  • Swiftの安全性について
  • ネイティブアプリのテスト、特にUI Test

についての話が多かったように思います。
特にテストについては、質問でもそれに関連した質問が多かったですし、やはりどこもテストについては苦労しているんだな、と。

また、講演の内容によっては自分もやっているようなことについての話もあったので、これはもっとちゃんとブログを書いて情報発信をしたほうがみんな幸せになれるかもれしないな、と。
本ブログではアプリについてあまり書いてないですが、今後は積極的に書いていこうかと思います。

あ、あと夕方ぐらいにMacのバッテリーが持たなくて、最後はiPhoneで講演をメモっていました。
Macのバッテリーを長持ちさせるにはどうしたら良いんだろうか?

とにもかくにも、とても刺激的な一日でした。
明日もまたtry! Swiftに行ってきます!
ではまた明日。

Read More

AWS Elastic TranscoderとKey Management Serviceを使って素敵にHTTP Live Streaming

HTTP Live Streamingとは

HTTP Live Streaming(HLS)というのがあります。
https://developer.apple.com/streaming/

Apple神が作った映像や音声のストリーミングプロトコルです。
ざっくり言うと、音声ファイルを短く分割したリソースファイル(.ts)と、分割したファイルを管理するプレイリストファイル(.m3u8)の2つを使って、HTTPプロトコルにのっとってダウンロードしつつ再生すればいいじゃん、的なやつです。
既存のプロトコルベースだし実装が単純なので色んな所で使われています。
最近だとAbemaTVとか。

これが便利なのは、リソースの暗号化と、回線に応じたリソースファイルの出し分けが規定されているのです。
https://tools.ietf.org/html/draft-pantos-http-live-streaming-20#section-4.3.2.4
https://tools.ietf.org/html/draft-pantos-http-live-streaming-20#section-4.3.4.2

この規定にのっとって、複数のビットレートのリソースファイルと暗号化キーを用意しておけば、あとは何も考えずに対応するプレイヤーにぶち込めが勝手にいい感じに再生してくれる、と。
あら便利。
というわけで、コイツをAWSのElastic Transcoderと、暗号化キーを管理するKey Management Serviceを使って、リソースファイルと暗号化を自動化できないかなー、と思ってやってみたらできたのでメモ。

作り方

  1. Identity and Access Management(IAM)のページのメニューにある、Encryption keys(日本語だと暗号化キー)の項目からKey Management Serviceに飛ぶ。(わかるかこんなの)
  2. KMSでで暗号化キーを作る。キモはTranscoderで使うS3のバケットと同じリージョンで作ることと、キー管理者とキーユーザーに”Elastic_Transcoder_Default_Role”を指定すること。これをやらないと何度やってもエンコードエラーになる。
  3. TranscoderでPipelineを作る。ここではEncryptionの項目に、先程KMSで設定したマスターキーのARNの設定をすること。

  1. TranscoderのJobを作る。出力するビットレート毎にOutput Detailsを作り、Playlistの項目は一つだけでOutputs in Master Playlistの項目に、Output Detailsで設定したOutputをすべて追加する。

  1. おもむろにCreate New Jobを押して出来上がりを待つ

確認

ファイルの確認

今回エンコードされたファイルはこんな感じ。

Test001
├── 160k
│   ├── track.key
│   ├── track.m3u8
│   ├── track00000.ts
│   ├── track00001.ts
│   ├── track00002.ts
│   ├...
│   └── track00064.ts
├── 64k
│   ├── track.key
│   ├── track.m3u8
│   ├── track00000.ts
│   ├── track00001.ts
│   ├── track00002.ts
│   ├...
│   └── track00064.ts
└── Test001.m3u8

マスタープレイリストのTest001.m3u8の中身はこんな。

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=189000,CODECS="mp4a.40.2"
160k/track.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=89000,CODECS="mp4a.40.5"
64k/track.m3u8

それぞれのリソースのプレイリストはこんな感じ。

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:11
#EXT-X-KEY:METHOD=AES-128,URI="track.key",IV=0x420473ab30beeaabfe1aa878fda4b312
#EXTINF:10.007800,
track00000.ts
#EXTINF:10.007789,
track00001.ts
#EXTINF:9.984567,
track00002.ts
...
#EXTINF:0.116089,
track00064.ts
#EXT-X-ENDLIST

問題なさげ。

再生テスト

Test001ディレクトリー以下を全部ダウンロードしてきて、マスタープレイリストをVLCメディアプレイヤーにつっこんだらちゃんと再生できるか確認。

あと、
http://dev.classmethod.jp/smartphone/iphone/network-link-conditioner/
にあるNetwork Link Conditionerを使って回線速度を制限して、ちゃんと64kbpsのファイルがダウンロードされるかどうかを串刺して確認。

できた。

Read More

Swiftでぬるぽをなくす技術

夏休みの宿題は提出日まで何もしない子供でした。はい。
この文章はWanoグループAdvent Calendarの17日目として書かれたものですが、諸事情で公開が遅れました。
多分この記事はは20日分になると思います。
アドベントカレンダーは土日にしないほうが良いという気づきを得た
 

本題

Swiftは良い言語なんですよ。Swiftは。
去年辺りから弊社でiOSアプリの開発を担当するようになって、それまでサーバーサイドでPerlとかを触ってた人間がSwiftに触れて、思ったんですよ。あー、これ良い言語だなって。
今日はその辺をつらつら書いていきたいと思います。
 

みんなぬるぽで死ぬ

みんな大好きNull Pointer Exception!
 

これはサーバーサイド全般に言えると思うんですけど、何かのタイミングでぬるぽで死んでもまぁ、daemontoolsとかsupervisordとかで再起動すれば良いので、基本動作に問題なければ、そこまで致命的じゃないと思うんですよね。
エラー画面も出るし。いや、まぁ、ダメなんですけど。
 

ただアプリの場合は、ぬるぽで死んだときは突然アプリの画面からホーム画面に切り替わるんですよ。
突然ですよ?500エラー画面とかもなしですよ?ビビりません?
ユーザーからしたら、は?なにこれ何いきなりホーム画面に飛んでんの?意味わかんないんだけど?
ってなるじゃないですか。
 

しかもサーバーサイドはエラーを監視しておいて、エラー通知をslackかなんかに飛ばせば、開発者はそれを見てすぐに対応できるじゃないですか。
だからぶっちゃけ5分後にはエラーを修正することができる。理論的には。
いや、めっちゃうらやましいんですけど。なによそれ。ずるくない?
 

こちとら審査っていうね、Apple神にお伺いをたてる儀式をしてですよ、万が一お伺いで逆鱗に触れたら英語で罵倒しあうわけですよ。
しかも罵倒した結果、お前のアプリクソだからださねぇ、ってApple神に言われたらおしまいですからね。
そこは穏便に行かないといけないわけですよ。
 

いや、何が言いたいかって言うと、iOSアプリは修正版を適用するのに時間がかかるんですよね。
最近は審査が早くなったからまだマシになったけれども、昔は最低1週間とかかかってましたからね。
しかもそのあとアプリを更新するかどうかはユーザー次第じゃないですか。
あれ意外とみんな更新してくれないんですよ。
 

となるとアプリを制作するにあたって、最初からぬるぽをなるべく潰していきたいわけですよ、なるべく。
ところがPerlとかJavascriptとかどうよ。
実際に動かしてみて、warnとかconsole.logとかで出力して初めて、あ、この変数nullだわ。そりゃこの処理死ぬよなー、ってわかるじゃないですか。
なにそれ、いちいち全部の動作を試さないといけないの?苦行なの?
って思うわけですよ。
 

ところがですよ、Swiftはぬるぽかどうか明示しなければいけない言語(Null安全)なので、予めプログラムを静的解析する時点で、こいつぬるぽになりそうだな、となるとここで処理が死にそうだな、ってわかるんですよ。
っていうかそういう不定な部分がある時点でコンパイルが通らないようになってるんですよ。
 

しかも、じゃあそこでNullチェックを入れようと処理を書くんですけど、そもそもの言語仕様としてNullチェックが書きやすいようになってるんですよ。
なにこれ、神なの?Apple神がまた新たな神を作っちゃったの?って思ったわけです。
 

Optionalという考え方

とりあえず以下のSwiftで書かれたクラスを見てください。

class HogeClass {
    var hoge: String
    var fuga: String?
    var piyo: String!

    init(){
        self.hoge = "hogehoge"
    }
}

このように、Swiftには型名のあとに、?とか!とかがつけられます。
 

?が付いている型はOptional型というものです。Nullを許す型です。
!が付いている方はUnoptional型というものです。Nullを許さない型です。
何も付いていない場合は不定です。どこかで明示的に代入をしない限り(Unoptional型と明示しない限り)コンパイルが通りません。
このHogeClassの場合、hogeプロパティが不定なので、明示的にinitで代入処理をしているんですね。
 

hogeは確かに見ればNullじゃないことは明らかなので問題はないと。
あれ、じゃあこのfugaとかpiyoプロパティってどうなのよ、って思いますよね。思います。
ここでPerlとかにあるように、オブジェクトのメソッドを実行して、nullだったら処理がどうなるかみてみましょう。

class HogeClass {
    var hoge: String
    var fuga: String?
    var piyo: String!

    init(){
        self.hoge = "hogehoge"

        let splittedHoge = self.hoge.components(separatedBy: ".")
        let splittedFuga = self.fuga?.components(separatedBy: ".")
        let splittedPiyo = self.piyo.components(separatedBy: ".") //ここで死ぬ
    }
}

はい、死んだ。
(.components(separatedBy:)はPerlで言うsplitみたいなやつです。)
 

これを見ると、fugaプロパティの処理では死んでいませんが、piyoプロパティの処理で死んでますね。
これはどういうことかというと、

  • 明示的に!をつけた型の場合、コンパイラはNullではないことを信じて処理を実行します。
  • 明示的に?をつけた方の場合、コンパイラはNullである可能性があるので、勝手にチェックしてnullの場合は処理を実行しません。(なにもしないのと同じ。)
     

これの何が嬉しいの、って話ですけど、ようは明示的にNullであるOptional型の場合、実行しても死なないんですよ。
PerlでTengを使って処理をする時に、

my $row = $teng->single("hogeTable", {id => 1});
$row->get_columns() # 死んだ

ってことがないんですよ。
また、Nullじゃない型の場合は、死ぬ、逆を言えばそこで処理を殺すことができるんですね。
逆にここがNullだとアプリがまともに動かない、プロダクトとして成り立たない、みたいな話の場合、あえて殺すことでデバッグ時に気付けるようにすることもできるんです。
(普通はエラー処理とかするのであまりやらないけど。)
 

となると次は、Nullの時になにもしないのは困るし、かと言って死ぬのも困る。普通にNullの時に別の処理をしたいんだけど、ってなりますよね?なります。
その場合はfugaに対してこうやって書けば良いんです。

class HogeClass {
    var hoge: String
    var fuga: String?
    var piyo: String! = "piyopiyo"

    init(){
        guard let unwrappedFuga = self.fuga else {1
            print("Fuga is Null")
            return
        }

        self.hoge = "hogehoge"

        let splittedHoge = self.hoge.components(separatedBy: ".")
        let splittedFuga = unwrappedFuga.components(separatedBy: ".")
        let splittedPiyo = self.piyo.components(separatedBy: ".")
    }
}

guardはif notみたいな意味の処理だと思ってください。
これは、

  • self.fuga、という変数をUnoptionalの変数(unwrappedFuga)に代入できたら処理を続ける
  • それ以外ではprint文でエラーを吐いて処理を終わらせる

ということをやっているんです。
 

Swiftではif文(guard文)でこのようにUnoptional型の変数に突っ込んでキャストすることが出来ます。
この処理をunwrapする、と言います。(また、!をつけることをForce Unwrapする、と言います。)
こうすることで、Nullの場合のエラー処理を書けるし、以降の処理はNullではない前提で処理を書けるようになるので楽になる、という感じです。
 

また、if文と違い、guard文はSwiftの言語仕様として、処理の最後にかならずreturnかbreakを書かなければいけません。
どういうことかというと、guard文を書いたときは、自然と条件に合わない場合は処理を弾く、という書き方になるのです。
この場合、文字通りぬるぽをguardする処理になります。
これ結構便利なんですよ。
他の言語にもこの仕様がほしいと何度思ったことか。
 

まとめ

このように、SwiftではNull安全の考え方、guardのようなNull安全に書ける言語仕様がそろっているので、とても安全に書きやすいのです。
ほかにもprotocol、extensionをはじめ、色々と安全に書く仕様が揃っているので、アプリを作るのにはもってこいの言語だと思います。
もちろん適当にForce Unwrapしまくって処理を書いていればいくらでも死にますが、そうならないように書ける、もしくは書きやすい言語というのはエンジニアとしては嬉しいのではないでしょうか。
 

Swiftをちゃんと書くようになると、Perlのような型もNull安全もない言語は恐怖すごいと思います。
そのうち、サーバーサイドがそのような言語で書かれた場合にどうやって厳密にNull安全を担保するか、というつらみ方法を書けたらと思います。
 

みんなSwiftにすれば良いのに。

Read More

Ubuntuでのvirt-managerを使った仮想環境の構築

Ubuntuでのvirt-managerを使った仮想環境の構築をした。

参考にしたのは

http://symfoware.blog68.fc2.com/blog-entry-962.html

とか

http://d.hatena.ne.jp/m-kawato/20090426/1240699832

とか。

 

端末からとりあえず

$ sudo apt-get install kvm libvirt-bin
$ sudo apt-get install virt-manager

でKVMとvirt-managerをインストール。

この辺で少し試行錯誤していたので、他にも必要なものをインストールする必要があるかもしれない。

また、場合によってはlibvirtdグループに自分のユーザーIDを登録する必要があるらしいが、自分の場合は自動で追加されていた。

 

virt-managerをインストールし終わったら、

$ virt-manager

で起動。

ここから「新しい仮想マシンを追加」を選択して、仮想マシンをインストール。

この辺は画面の指示に従ってやればいいと思う。

 

インストールが終わったら、一旦ホストマシンの端末を立ち上げて、

$ vim /etc/network/interfaces

とやってホストマシンの仮想ブリッジの設定を書く。

DHCPを使う場合はこんな感じ

auto lo
iface lo inet loopback

auto eth1
iface eth1 inet dhcp

auto br0
iface br0 inet dhcp
bridge_ports eth1

固定IPの場合はこんな感じ

auto lo
iface lo inet loopback

auto eth1
iface eth1 inet dhcp

auto br0
iface br0 inet static
    address 192.168.1.50
    netmask 255.255.255.0
    broadcast 192.168.1.255
    gateway 192.168.1.1
    dns-nameservers 192.168.1.1
    bridge_ports eth1

ここで、自分の場合はeth0ではなくeth1だったことに気づかずに無駄に時間を食った。

 

一通り終わったら、ここでホストマシンをリブート。

リブート後、再度virt-managerを起動して、「仮想マシンの情報を表示」をクリック。

その中の、仮想ネットワークインターフェース -> ソースデバイス より先ほど作った仮想ブリッジ名を選択。

自分の場合は「ホストデバイス eth1(Bridge ‘br0’)」だった。

これを忘れてまたハマる。

 

設定が終わったら仮想マシンを再起動して、仮想マシンにpingが通ったら完璧!

これでようやくテストサーバーが組める。

ふぅ…。

Read More