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

AWS Step FunctionsでLambda Functionでのサムネイル画像作成をシンプルに

この記事はWanoグループ Advent Calendar 2016の23日目の記事です。
Wanoグループ内でのLambda推しエンジニアとして、前回のLambda@Edgeに引き続き、2016年Re:Inventで発表された、AWS Step Functionsについての書いてみたいと思います。

AWS Step Functionsで解決できること

なんと言っても以下の2点だと思います。

  • Lambda Functionを小さい単位で維持できる
  • Lambda Function間の連携にSQSやDynamoDB等を使用する必要がなくなる

Wanoでも複数のLambda Functionを活用していますが、1つのFunctionの中でいろいろなことをやりすぎたため、他のサービスにそのまま転用できなかったり、コードの見通しが悪くなったりと言ったことが出てきました。
1つ1つのFunctionを細かく分けて、SQS等を使用して連携されることも検討しましたが、リトライや分岐のためにFunctionを用意しないといけないといったことを考えると、腰が重くなっていました。
その問題点を解決してくれるのがAWS Step Functionsです。

Lambda Functionの事例で見かけるサムネイル画像作成をStep Functionsで

Lambda Functionsの事例として、サムネイル画像を作成するサンプルをよく見かけます。
この記事でもサムネイル画像作成を例にし、以下のサムネイル画像あるあるを解決する処理をLambda FunctionとStep Functionsで実現したいと思います。

サムネイル画像あるあるとは

  1. せっかくサムネイル画像で小さくしたのに、Google PageSpeedで調べたら、ロスレス圧縮したら46%小さくなるよと言われる
  2. 適切なContent-Typeヘッダーが付いておらずブラウザで想定外の挙動をする
  3. Cache-Controllヘッダーが付いておらずブラウザキャッシュが効かない

勝手にあるあると言っているだけで、私が良く忘れるだけという可能性が大きいです。。。が、今回はこれを解決することを前提として、進めたいと思います。

Lambda Functionを実装する

Lambda Functionを小さい単位で維持することが重要なので、以下の機能で分けてLambda Functionを実装したいと思います。

  1. ResizeImage: 画像をリサイズするFunction
  2. MinifyJpeg: JPEG画像をロスレス圧縮するFunction
  3. MinifyPng: PNG画像をロスレス圧縮するFunction
  4. SetMeta: メタデータを設定するFunction

実装できたら、これらのLambda Functionを予めデプロイしておきます。
ちなみに私は以前apexを使っていましたが、最近serverless frameworkに乗り換えを進めています。
その内この辺りも記事にできたらなと。

AWS Step Functionsを設定する

State Machineを作る

Step Functionsの設定画面でState Machineを作ります。
設定ファイルは以下です。

注意
2016年12月23日時点で、State Machineの修正はできません。State Machineの設定ファイルもバージョン管理対象としておくことを強くおすすめします(泣きを見ました。。。)
{
  "Comment": "An example of the Amazon States Language using a choice state.",
  "StartAt": "ResizeImage",
  "States": {
    "ResizeImage": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:FUNCTION_NAME",
      "Next": "JpegOrPng"
    },
    "JpegOrPng": {
      "Type" : "Choice",
      "Choices": [
        {
          "Variable": "$.object.fileType",
          "StringEquals": "jpeg",
          "Next": "MinifyJpeg"
        },
        {
          "Variable": "$.object.fileType",
          "StringEquals": "png",
          "Next": "MinifyPng"
        }
      ],
      "Default": "UnsupportedImage"
    },
    "MinifyJpeg": {
      "Type" : "Task",
      "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:MinifyJpeg",
      "Next": "SetMeta"
    },
    "MinifyPng": {
      "Type" : "Task",
      "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:MinifyPng",
      "Next": "SetMeta"
    },
    "UnsupportedImage": {
      "Type": "Fail",
      "Cause": "No Matches!"
    },
    "SetMeta": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:SetMeta",
      "End": true
    }
  }
}

上記ファイルでの設定結果として以下のState Machineができます。

State Machineを実行する

State Machineができたら、早速実行してみましょう。
Lambda Function同様コンソールからJSONを指定して実行できますので、そちらで実行します。

動きました!!
今回は、JPEG画像をイベントとして渡したので、MinifyJpegに遷移しています。
PNG画像を渡せばMinifyPngに遷移する。。。はず(もう23日が終わりそうなので、試す時間がなかったり。。。)

State Machine実行時の注意点

注意点としては、Lambda Functionの実行ではなく、State Machineの実行という点です。
今回StartAtに指定したResizeImageが起動するイベントを実行してもState Machineは実行されず、State Machineの起動が必要になります。
残念ながら、現時点ではState Machineをイベントドリブンにすることはできないようです。
実運用では監視したいイベントを割り当てたLambda Functionを用意して、そちらからState Machineを実行するような構成にする必要があります。

まとめ

いくつかの課題はあるものの、AWS Step Functionsを使うことで、Lambda Function間の連携がシンプルになることは間違いありません。
課題自体も恐らく時間の問題で改善されると思いますし、serverless frameworkといった周辺ツールも続々対応してくると思うので、今後も注目です!!

Read More

MACで Go言語の開発環境(Go+Vundle+Vimgo+gocode)セットアップ

この記事はWanoグループ Advent Calendar 2016の16日目の記事です。

(2016年12月 Version)
1. GO install

https://golang.org/dl/

Apple OS X (OS X 10.8 or later)
go1.7.4.darwin-amd64.pkg (79MB)

2. Goのpath設定 (~/.zshrc編集)

export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin

テスト方法(hello world):
(1) Create the project

 mkdir -p $GOPATH/src/github.com/user
 mkdir $GOPATH/src/github.com/user/hello
 vim $GOPATH/src/github.com/user/hello/hello.go

(2) Install it

	go install github.com/user/hello

(3) Run it

cd $GOPATH/bin
./hello

3. Vundle install

	mkdir ~/.vim/bundle
	git clone https://github.com/VundleVim/Vundle.vim.git 

4. Vundleの設定(~/.vimrc編集)

	set nocompatible         " be iMproved, required
	filetype off                  " required
	set rtp+=~/.vim/bundle/Vundle.vim
	call vundle#begin()
	
	Plugin 'VundleVim/Vundle.vim'
	Plugin 'fatih/vim-go'
	Plugin 'nsf/gocode', {'rtp': 'vim/'}
	
	call vundle#end()            " required
	filetype plugin indent on    " required

5. Vimで:PluginInstall実行する (Vimgoとgocodeのインストール)
GoFmt :ソースコード整形
ctrl+x,ctrl+o (順番に連発) : 自動補完機能

Read More

Android Deeplinkを特定のパスにのみ対応させる

Wanoグループ Advent Calendar 2016の11日目の記事になります。11日目の44時くらいです。決して12日目ではない。

AndroidのDeepLink設定のメモ。

https://xxx.com/release/***

https://xxx.com/item/***

のような2つのパスのみにアプリが反応するように以下のように組んでいた。

 <activity android:name=".Container.Routing.RoutingActivity">
   <intent-filter>
   <action android:name="android.intent.action.VIEW" />

   <category android:name="android.intent.category.DEFAULT" />
   <category android:name="android.intent.category.BROWSABLE" />

   <data android:scheme="http" />
   <data android:scheme="https" />
   <data android:host="xxxx.com" />
   <data android:pathPrefix="/artist/" />
   <data android:pathPrefix="/item/" />
   </intent-filter>
 </activity>

  
しかしこれでは該当のパス以外のURLにも反応してしまっていた。
  
そこでリンクを以下のように修正。

...
 <intent-filter>
   <action android:name="android.intent.action.VIEW" />
   <category android:name="android.intent.category.DEFAULT" />
   <category android:name="android.intent.category.BROWSABLE" />
   <data
     android:scheme="https"
     android:host="xxxx.com"
     android:pathPrefix="/artist/"
   />
 </intent-filter>

 <intent-filter>
   <action android:name="android.intent.action.VIEW" />
   <category android:name="android.intent.category.DEFAULT" />
   <category android:name="android.intent.category.BROWSABLE" />
   <data
     android:scheme="https"
     android:host="xxxx.com"
     android:pathPrefix="/item/"
   />
 </intent-filter>
 </activity>

当面はこれで該当のパスにのみDeepLinkが適用されるようになった。

Read More

AndroidのWebViewの思い出

Wano の 伏見です。
この記事はWanoグループ Advent Calendar 2016の9日目の記事になります。

この記事に関しては死亡事故のたびに随時追記するかも。

webViewのCookieの同期で死亡

Android WebViewのCookieの扱いで激ハマりした話
この記事と違って4.4系では死ななかった。4.2ではものも言わずアプリは死にました。

そもそも4.4までのCookieマネージャがdeprecatedなので分岐大変

最新のOSのWebViewでアブないサイトに対応する

http/https混在環境で mixed contentsの設定をガバガバにします。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    webView.getSettings().setMixedContentMode( WebSettings.MIXED_CONTENT_ALWAYS_ALLOW );
}

アブないOSのWebView でセキュアなサーバーに接続する

デフォルトで SSlv3 で通信するようになっている OS の場合、
OkHttp や HttpUrlConnection などの通信系ライブラリは、通信前にGooglePlayServicesから動的にパッチを当てれば、TLS1 ~ 1.2系が使えるようになる場合があります。

同期的にパッチを当てる場合

try {
    ProviderInstaller.installIfNeeded(getActivity());
} catch (GooglePlayServicesRepairableException e) {
    e.printStackTrace();
} catch (GooglePlayServicesNotAvailableException e) {
    e.printStackTrace();
}

それでも4.3以前の デフォルトWebView では SSLv3 を 使ってしまうことがある。対応できません

通信の上書きにも限界があるでしょう。

学び

  • アプリサイズがかなり大きくなることと引き換えに、代替WebViewのCrossWalkを使おう
  • でも基本的にしょうもないものはどんどん捨てよう
  • 要件定義で殺そう
  • iOS8や4.3系以下はセキュリティ的にもはや危ないし、シェア的にも対応コストの方が高いという認識を周知していこう

それはそうと

ECサイトとかのトラッキング & 広告系 のタグ , ページのロードをブロックしながら document.write()しててChrome先生のコンソールで怒られまくってるんですが、そろそろ消されますよ?

Read More

AppleScriptでPerlのcommandを実行する

この記事はWanoグループ Advent Calendar 2016の6日目の記事です

AppleScriptとは?

AppleScript は、OS X に組み込まれている、多目的なスクリプト言語です。AppleScript を使ってショートカットを作成したり、繰り返しのタスクを自動化したりできます。さらに、そのアイコン上にファイルまたはフォルダをドラッグ&ドロップしたときに実行出来ます。今回紹介する例は、デスクトップからドラッグ操作でファイルを移動して、AppleScriptでPerlのcommandを実行するものです。

まず、スクリプトエディタを選択して起動します。

scripteditor

スクリプトエディタ

 

ドラッグ操作なので、そのスクリプトの実行を開始するには、「on open」ハンドラを必要とします。「on open」ハンドラには、ドロップレットにドラッグしたファイルのオブジェクトのリストが入ります、以下の例を示します。

on open (theItemsDropped)
  (first command)
  (second command)
   …
end open

 

実際のコード:


on open these
  # 複数ファイル対応
  repeat with this in these
    set filename to POSIX path of this
    # tellコマンドを使ってFinderにiTermを開くように命令します
    tell <i>application</i> "iTerm"
      # activateは指定されたウインドウを開き、手前に移動します
      activate
      #iterm中でdefault profileの設定をして、新しいiTermのwindowを開きます
      set new_term to (create window with default profile)
      tell new_term
        tell the current session
        #FileToAction.plにiTermでファイル実行する
        write text "perl /Users/johnny/src/test/FileToAction.pl" & filename
        end tell
      end tell
    end tell
  end repeat
end open

ファイルを扱うには、スクリプトのままではなく、.appファイルで保存します。

そうすると、エンジニア以外の人でも、簡単にファイルをドラッグして、Perlのcommandを実行する操作できます。

Read More

Sublime text布教

この記事は1日目から頓挫しかけて慌てて書いたWanoグループ Advent Calendar 2016の1日目です。

Wanoは少々珍しく、デザイナー兼コーダーの皆さんはWindowsが多いです。
エディタは各々好みのものを利用していますが、参考までに私の使っているエディタを紹介していこうと思います。

エディタ

Sublime text 3

使用パッケージ

  • IMESupport…日本語をインラインで入力できるように
  • Japanize…メニューの日本語化
  • SimpleClone…タブの複製
  • SublimeServer…ローカルサーバー
  • SFTP
  • COMPASS…SASSのコンパイル
  • SCSS…scssファイルを扱えるように

と、最小限の構成です。COMPASSを使うにはRubyが必要等もうひと手間かかります。
特に便利だと思っているものは太字にしてあるので、今後詳しく紹介します。

Sublime textのいい所は拡張性が高い等が言われていますが、何よりも環境の引っ越しが楽というのが使っている理由です。
C:\Users\ユーザー名\AppData\Roaming\Sublime Text 3\
内のファイルと
Preferences.sublime-settings
の内容を丸ごとコピペするという2ステップで環境の引っ越しが完了します

次回からは各パッケージのインストール方法や、細かい設定、ショートカット等を紹介できればと思います。
エディタで迷っている方がいれば参考になれば幸いです。

Read More