try! Swift 2017 Tokyo に参加してきた - 2日目:午前
さて2日目です。
https://www.tryswift.co/tokyo/jp
1日目と同様にその場でのメモと感想を書いていきますが、ちょっとボリュームが大きいので午前・午後の2つに記事を分割したいと思います。(個人的に見返しやすくもあるので)
テスト可能なコードを書くということの2つの側面
メモ
- 冒頭
- なぜテストをするか?
- テストできるコードだけテストする
- 関数型で書くのは良い
- テストをドキュメント化する
- エッジケースも十分に考慮する
- compute(file:) -> Int
- 単純に見えてもいろんな値を参照している
- Bundle
- String(contentsOfFile:)
- 副作用がある
- Consoleへ出力
- なぜテストしづらいか?
- ハードドライブという外部の状態に依存する
- コンソールへの出力を確認する必要がある(外部に影響を与えていないか)
- 2つの世界
- インプット
- アウトプット
- 単純に見えてもいろんな値を参照している
- 副作用
- OUTPUT
- 我々は慣れているので考えやすい
- 影響がないか確認する必要がある(それ単体ではなく連鎖的に反応していないか)
- 副作用のあるコードを境界部分にのみ持ってくる
- 戻り値をIntの代わりに(Int, String)にしてコンソール出力を無くす
- INPUT
- Co-effects - 共作用
- INPUTは共作用のテスト
- 他のグローバルな関数を参照している
- Co-effects = アウトプットを出すための前提条件
- 言い換えると、それがないと結果を出せないようなもの
- やりかた
- すべてをstructに入れ込む
- apiService: ServiceProtocol
- cookieStorage: HTTPCookieStorageProtocol
- currentUser: User?
- dateType: DateProtocol.Type
- language: Language
- mainBundle: BundleProtocol
- reachability: SignalProducer<Reachability, NoError>
- scheduler:
- userDefaults: UserDefaultsProtocol
- 日付を取るのはCo-effectsのわかり易い例
- 日付を参照すると副作用がある
- バンドルも当然Co-effects
- 通信状態も
- Rxにおけるスケジューラも
- 当然UserDefaultsも
- すべてをstructに入れ込む
- リファクタリング
- バンドル
- 成功 or 失敗
- 全部引数に持ってくる
- 宣言が複雑にみえるけれど副作用が宣言部分に集約されている
- セルフドキュメンテーションに繋がる
- バンドル
- Co-effects - 共作用
- OUTPUT
- 結論
- なぜテストが難しいかというとCo-effectsがある
- グローバルに自由に参照しないように、strutctを用意して、それを利用するようにする
- そこに副作用をすべて集約する
- FAQ
- 1
- バグレポート = 失敗したテスト
- テスト駆動をよくやっている?
- 2
- ReaderMonad / StateMonad
- あまり意識していない
- プロパティベースのテストを行うのか
- やりたいとは思っているが、まだ行っていない
- ReaderMonad / StateMonad
- 1
断片メモコード
ファイル名を受け取って、その行数を返す関数
file: String = "number.txt" -> compute(file:) -> Int (12345)
感想
どうやって品質の良いテストコードを書くか、という話。
テストするための2つの要素「インプット」「アウトプット」について非常に詳しい説明がありました。もっとも一般的な入出力の話ではなく、副作用についての話でした。
発表者も言われてましたが「アウトプット」、例えばDatabaseやファイルを書き換えたり、iOSであればUserDefaultsを書き換えたり、という副作用は考え慣れているので簡単だけれど、「インプット」についてはあまり考えなかったりする、とのこと。
その前提条件となる「インプット」のことを「Co-effects(共作用)」というらしいが、それは最近の研究で話に上がってきたものらしく、あまり広まっている用語ではない模様。具体的には「現在時刻」などがわかり易い例で、アウトプットを出すための前提条件となるものが「共作用」と呼ばれるようです。グローバル関数もその例に当たる、と。
ではどうやって解決するかというと、インターフェースをプロトコルとして宣言して、そのプロトコルを引数として全部渡せば良い、とのこと。
たしかに関数の宣言は複雑になってしまうけれど、副作用がその一箇所に集約されるので、結果的に品質が安定するとのこと。(副作用のあるコードを境界部分のみに集約する)
そしてテストではなく実際の値を返すプロトコルの実装群は、グローバルなStructにまとめておくと良いとのこと。
などなど、私にとっては得るものが大変多いセッションでした。
ちなみに質問でReaderMonadを使わないのか、プロパティベースのテストは行っているのか、といった、非常にレベルの高い質問がされていました。
誰もが知りたいSequenceとCollectionのすべて
メモ
- 構造
- BidirectionalCollection
- Collection
- Sequence
- Sequence
- Collection
- 要件
- Sequenceを引き継ぐ
- 有限
- 何回もIterateできる(Sequenceは1回)
- 実装
- Indexを持つ
- start / end
- APIErrorCollection
- privateだとアクセス出来ないので?
- 要件
- BidirectionalCollection
- 要件
- Collectionを引き継ぐ
- 前にも戻れる
- 実装
- afterに加えてbeforeが追加される
- 要件
- 他
- RandomeAccessCollection
- その値に直接
- RangeReplaceableCollection
- 中間値を変換?
- Appleのドキュメントを見ればいろいろ分かる
- RandomeAccessCollection
- FAQ
感想
Swift の Iterator、Sequence、Collection、BidirectionalCollection について、どんな感じになっているのか詳しく見ていこう、という話。
微妙に理解が怪しい部分だったのだけれど、順を追った分かりやすい説明だったので、頭が整理されたような気がします。
個人的には xs.filter(predicate).count
ではなく、 xs.count(predicate)
という書き方が勉強になりました。もしかしたら Advanced Swift あたりで一度見ていたかもしれないけれど。
あとは EachPair の実装方法も面白かったです。
簡単にまとめると、以下のような感じでしょうか。 - Iterator:任意の値列を返す - Sequence:1回だけIterateできる - Collection:複数回操作できる - BidirectionalCollection:前にも戻れる
もう一度自分でコードを書いて、理解を深めておきたいところです。
様々な場面でSwiftを使う
メモ
- Apple以外のプラットフォームの話
- サーバサイドSwift / ライブラリ
- OSS
- Apple以外のプラットフォーム
- Web
- マイクロサービス
- Deamon、Utility、Tool
- なぜ?
- 型付けされている
- サーバサイドSwift
- 個人プロジェクト
- ポイント
- SPM
- Node.jsのnpmに似ている
- シェバンで使うと簡単なスクリプトとしても使える
- まとめ
- 安全で効率的
- OSS
- Cベースのライブラリ使える
- FAQ
感想
Swiftをサーバサイド(Mac、Linux)やボードコンピュータ(ラズパイ)とかで動かす、という話。既存のPythonのAPIの設計がイケてなくてパフォーマンスも改善したかったので、せっかくだからSwiftを使ってみた、とのこと。
他のセッションでもあったけれど、C言語のABIが安定していて、かつSwiftがLLVMを利用しているので、既存のC言語の資産を使えるとのこと。
実際にSwiftで開発したことで、いろいろと面倒なこともあったのではないかと思うけれど、そのあたりの話があまりなかったので、実際のところはどうなのだろうとは思います。
ただ実績として20日間動いているとのことなので、サーバサイドSwiftはもう実プロダクトとして利用できるレベルには達したのかな、と感じます。
⚡️🎤 VRの革新と新たなユーザー体験
メモ
- VRをゲーム以外でも
- 360°のVRが重要になってきている
- ティム・クックはARは重要だと発言している
- 事例
- ショッピング(Alibaba)
- VRショッピング(自宅にいながら有名なショップで買物)
- 不動産
- 360°の写真を取って、それを見られるようにする
- 自動車
- デザインやアクセサリの変更
- 美しい形式でのドライブ
- 店舗のスペース削減にも
- ニュース・メディア
- 360°の放送
- 自らが実際に居るような体験ができる
- NewYork Times
- 運動
- スケートのイメージトレーニング
- 実際に効果があるとのこと
- ショッピング(Alibaba)
感想
VR(AR)が実際にどのような箇所で効果的に利用されているか、という実績紹介。
個人的にあまり強い興味は持っていない分野だったのだけれど、かなり身近になってきたし、うまく活用すれば良いサービスが提供できるのだと感じた。
iOSにおけるDocument IndexingとApp Search
メモ
- 検索をアプリ内で
- App Search → ほとんど使っている人がいない
- App Search API
- Core Spotlight API
- private
- 大量のデータの時に便利
- 重要な属性
- expirationDate(有効期限)
- attributeSet(SpotLightで可視化)
- uniqueIdentifier(まとめて管理が便利?)
- プラクティス
- 非同期でバッチ処理をする
- コンテンツを常に最新にしていく
- Search Continuation(from iOS10)
- アイテムを探す時に便利?
- 注意
- beginBatch()はバックグラウンドスレッドで動く
- beginBatchするまえにendBatchしないとクラッシュ
- どうやってテストするか?
- 開発者設定 > すべてのアイテム?
- シミュレータでは機能しない(ので実機でテスト)
- NSUserActivity
- 見えるものだけが対象になる
- SearchebleItem
- Universal Link
- Webページからアプリへ直接遷移
- Core Spotlight API
- 統合する理由
- コンテンツへのアクセスが速くなる
感想
iOS9からのAppSearchについて、実装方法とかの話。
個人的にはAppSearchはそれほど良い使われ方をしているように感じないので、まぁ効果的だと感じる人もいるのだなぁ、というくらいの感想でした。
ただ実践でのノウハウが共有されたのはありがたいと感じました。
スタートアップのSwift
メモ
- Swiftの現場での経験(初心者からはじめて1年間)
- スタートアップ
- スタートアップは0から新しいものを作る、それもすぐに
- 製品の様々な面を自分たちでカバーする必要がある
- どうやって作るか?
- Parse + Swift = Fast (To write)
- CocoaPodsでいろんなOSSがあったので活用できた
- リリース
- 最初の2週間で10万人
- 予想外の人数
- 問題
- 秒間リクエスト数を超えてしまった
- リクエストを絞込
- お金を払っても解決しなかった
- 地域も絞る
- Slackとテストフライトでフィードバックを得られるように
- CEOがSlaskでクラッシュ解決を募集(再現している人)
- 一人来てくれたのでiPhoneを繋いで調査した
- ユーザ名が入っていなかった
- 他に問題
- 強制アンラップを使用しないように
- switchのデフォルトシンタックス
- 最初だから知らなかった
- Extension
- コードベースの改善に便利だった(丸くする、とか)
- 最初に書いたコードは捨てる時期にもなってきている
- Parseが閉じるアナウンス!
- Swiftのバージョン移行は大変だった
- Swiftの学習カーブは低い(短期間で習得しやすい)
- 秒間リクエスト数を超えてしまった
感想
スタートアップで Swift + Parse を利用した結果、サービスがどのように成長し、どのようなトラブルに巻き込まれかというリアルな話。
使いたいからではなく早く作るために Swift + Parse を採用し、その結果としてスケールしない問題に出くわしたり、それを解消するためにどのような対策を取ったのか。クラッシュの原因が分からない問題に対して、Slackでユーザを募集したり、そこからのフィードバックをいかに反映したか。そして Parse が閉じる事になった時に、どのようにデータ移行を行ったか。
などなど、非常に貴重な話を聞くことが出来ました。
外部サービスに依存した場合のリスクという話は以前からも聞いていましたが、今回の発表を聞いてそういったことが実際にあるのだという実感がわきました。
またクラッシュを解消するためにSlackでユーザを募集するというのは衝撃を受けました。日本でそんなことはまず出来ないと感じたからです。
try! Swift でスタートアップのリアルな話が聞けるとは思わなかったので、思わぬ誤算という感じのセッションでした。