SlideShare a Scribd company logo
Developer Day
続・ゲンバのSwift
1
D-1
安達 勇一
クラスメソッド株式会社
Ⓒ Classmethod, Inc.
2015年03月29日
#cmdevio2015
2
安達 勇一
• 2013/12 入社

• TwitterID:   
@UsrNameu1

• Github:   
https://github.com/UsrNameu1

• Blog:   
http://dev.classmethod.jp/
author/yad

•        で連載やって
ます
Topics for today
• Enum
• Collection API
• BrightFutures
3Ⓒ Classmethod, Inc.
Topics for today
• Enum
• Collection API
• BrightFutures
4Ⓒ Classmethod, Inc.
Enum
• 離散値とEnum
• リソースとEnum
• エラーとEnum
5Ⓒ Classmethod, Inc.
離散値とEnum
• 決まった数値のみ許容するAPIのEndpoint :
6Ⓒ Classmethod, Inc.
POST api/v1/user
[
{ "name" : "Tarou", "gender" : 1 },
{ "name" : "Yoko", "gender" : 2 }
]
離散値とEnum
• 決まった数値のみ許容するAPIのEndpoint :
7Ⓒ Classmethod, Inc.
POST api/v1/user
[
{ "name" : "Tarou", "gender" : 1 },
{ "name" : "Yoko", "gender" : 2 }
]
決まった数値以外は
400 Bad Request
離散値とEnum
• 対応するモデル
8Ⓒ Classmethod, Inc.
struct User {
let name: String
let gender: Int
}
離散値とEnum
• 対応するモデル
9Ⓒ Classmethod, Inc.
struct User {
let name: String
let gender: Int
}
違う、そうじゃない!
struct User {
let name: String
let gender: Gender
}
enum Gender: Int {
case Male = 1
case Female = 2
}
離散値とEnum
• 限られた値しかとらない数値はEnumにすることで…
→APIエラーを防げる
10Ⓒ Classmethod, Inc.
POST api/v1/user
[
{ "name" : "Tarou", "gender" : 1 },
{ "name" : "Yoko", "gender" : 2 }
]
決まった数値以外は
400 Bad Request
離散値とEnum
• 限られた値しかとらない数値はEnumにすることで…
11Ⓒ Classmethod, Inc.
switch user.gender {
case 1 : println(“male”)
case 2 : println(“female”)
default : assert(false, “error”)
}
離散値とEnum
• 限られた値しかとらない数値はEnumにすることで…
→網羅性チェックによりassertionを書く手間を省ける
12Ⓒ Classmethod, Inc.
switch user.gender {
case .Male : println(“male”)
case .Female : println(“female”)
}
13Ⓒ Classmethod, Inc.
離散値はEnumにして
IOを型として束縛
Enum
• 離散値とEnum
• リソースとEnum
• エラーとEnum
14Ⓒ Classmethod, Inc.
リソースとEnum
• Enumで宣言された値に対する
• NSLocalizedString
• UIImage
→Objective-Cではコンバータやカテゴリ拡張を
 別に実装するなどで対処。
15Ⓒ Classmethod, Inc.
リソースとEnum
• Enumで宣言された値に対する
• NSLocalizedString
• UIImage
→SwiftではEnumに直接書けるようになりました!
16Ⓒ Classmethod, Inc.
リソースとEnum
• NSLocalizedStringを性別に対して取得
17Ⓒ Classmethod, Inc.
enum Gender: Int {
case Male = 1
case Female = 2
}
extension Gender {
var localizedString: String {
switch self {
case .Male:
return
NSLocalizedString(“male”, comment: “”)
case .Female:
return
NSLocalizedString(“female”, comment: “”)
}
}
}
リソースとEnum
• UIImageを性別に対して取得
18Ⓒ Classmethod, Inc.
enum Gender: Int {
case Male = 1
case Female = 2
}
extension Gender {
var thumbImage: UIImage {
switch self {
case .Male:
return UIImage(named: “male”)
case .Female:
return UIImage(named: “female”)
}
}
}
リソースとEnum
• Before
• After
19Ⓒ Classmethod, Inc.
cell.thumbImage =
[UIImage thumbImageWithGender: gender];
cell.title =
[NSString localizedStringWithGender: gender];
cell.thumbImage = gender.thumbImage
cell.title = gender.localizedString
20Ⓒ Classmethod, Inc.
Enumに紐付くリソースは
自身で管理・記述を簡潔化
Enum
• 離散値とEnum
• リソースとEnum
• エラーとEnum
21Ⓒ Classmethod, Inc.
エラーとEnum
• Objective-Cでの典型的なエラーハンドリング
(ライトバック渡し)
22Ⓒ Classmethod, Inc.
NSError *error = nil;
NSData *aData =
[NSData dataWithContentsOfURL:pathURL
options:NSDataReadingUncached
error:&error];
if (!error) {
// エラーがない時の処理
} else {
// エラーがある時の処理
}
エラーとEnum
• エラーハンドリングについてはほぼ定形の処理
• エラーが無い時に続けて簡単に処理を書きたい…
• Optionalでは何のエラーかわからない…
23Ⓒ Classmethod, Inc.
エラーとEnum
24Ⓒ Classmethod, Inc.
• エラーハンドリングについてはほぼ定形の処理
• エラーが無い時に続けて簡単に処理を書きたい…
• Optionalでは何のエラーかわからない…
そのお悩み
Result<T>が
解決します!!!!
エラーとEnum
• Result<T>
25Ⓒ Classmethod, Inc.
public enum Result<T> {
case Success(Box<T>)
case Failure(NSError)
public init(_ value: T) {
self = .Success(Box(value))
}
}
public final class Box<T> {
public let value: T
public init(_ value: T) {
self.value = value
}
}
エラーの可能性
を持った値
コンパイラによるエラー
回避の為のBoxクラス
エラーとEnum
• Before
• After
26Ⓒ Classmethod, Inc.
- (NSData *)dataWithURL:(NSURL *)filePathURL
error:(NSError *)error
{
// エラーがあるときにはerrorにポインタを渡し
// エラーがない時にnilでないNSData*を返す。
}
func dataWithURL(url: NSURL) -> Result<NSData>
{
// エラーがあるときもない時もResult型を返す。
}
エラーとEnum
• map in Optional<T>
27Ⓒ Classmethod, Inc.
// Noneの可能性をもった値を
let someInt = “127”.toInt()
// Noneの可能性を保ったまま中身だけ変更
someInt.map { val in val + 1 }
エラーとEnum
• map in Optional<T>
28Ⓒ Classmethod, Inc.
Some
None
Optional<T> Optional<U>
map(f: T -> U)
T
None
U
None
f
エラーとEnum
• map in Result<T>
29Ⓒ Classmethod, Inc.
extension Result {
func map<U>(f: T -> U) -> Result<U> {
switch self {
case .Success(let box) :
return .Success(Box(f(box.value)))
case .Failure(let err) :
return .Failure(err)
}
}
}
エラーの可能性を保って中の値をマッピングする
エラーとEnum
• map in Result<T>
30Ⓒ Classmethod, Inc.
// NSErrorの可能性をもった値を
let someInt = Result(127)
// NSErrorの可能性を保ったまま中身だけ変更
someInt.map { val in val + 1 }
エラーの可能性を保って中の値をマッピングする
エラーとEnum
31Ⓒ Classmethod, Inc.
Success
Failure
Result<T> Result<U>
map(f: T -> U)
T
NSError
U
NSError
f
• map in Result<T>
エラーとEnum
• flatMap in Optional<T> (Swift 1.2)
32Ⓒ Classmethod, Inc.
// Noneの可能性をもった値を
let someStr: String? = “127”
// 中身があったら新しい
// Noneの可能性をもった値に変更
let someInt = someStr?.toInt()
Optional Chaining
エラーとEnum
• flatMap in Optional<T> (Swift 1.2)
33Ⓒ Classmethod, Inc.
// Noneの可能性をもった値を
let someInt = “127”.toInt()
// 中身があったら新しい
// Noneの可能性をもった値に変更する
someInt.flatMap { val as? UInt8 }
// Noneの可能性をもった値を
let someStr: String? = “127”
// 中身があったら新しい
// Noneの可能性をもった値に変更
let someInt = someStr.flatMap { str in
str.toInt()
}
エラーとEnum
• flatMap in Optional<T> (Swift 1.2)
34Ⓒ Classmethod, Inc.
// Noneの可能性をもった値を
let someInt = “127”.toInt()
// 中身があったら新しい
// Noneの可能性をもった値に変更する
someInt.flatMap { val as? UInt8 }
// Noneの可能性をもった値を
let someStr: String? = “127”
// 中身があったら新しい
// Noneの可能性をもった値に変更
let someInt =
someStr.flatMap(String.toInt)
無引数インスタンスメソッドを関数として扱う
エラーとEnum
35Ⓒ Classmethod, Inc.
Some
None
Optional<T>
T
None
f
flatMap(f: T -> Optional<U>)
Optional<U>
U
None
• flatMap in Optional<T> (Swift 1.2)
エラーとEnum
36Ⓒ Classmethod, Inc.
extension Result {
func flatMap<U>(f: T -> Result<U>) -> Result<U> {
switch self {
case .Success(let box) :
return f(box.value)
case .Failure(let err) :
return .Failure(err)
}
}
}
新しいエラー可能性を持つ値にマッピングしてマージ
• flatMap in Result<T>
エラーとEnum
• flatMap in Result<T>
37Ⓒ Classmethod, Inc.
// NSErrorの可能性をもった値を
let someInt = Result(127)
// 中身があったら新しい
// 新しいNSErrorの可能性をもった値に変更
someInt.flatMap{ val in Result(val + 1)}
新しいエラー可能性を持つ値にマッピングしてマージ
エラーとEnum
38Ⓒ Classmethod, Inc.
Success
Failure
Result<T>
T
NSError
f
flatMap(f: T -> Result<U>)
Result<U>
U
NSError
• flatMap in Result<T>
39Ⓒ Classmethod, Inc.
Enumでエラーの
可能性を持つ
値を作る
40Ⓒ Classmethod, Inc.
Topics for today
• Enum
• Collection API
• BrightFutures
41Ⓒ Classmethod, Inc.
Collection API
• 実践 CollectionAPI
• map, filter, reduce
• flatMap(Swift 1.2)
42Ⓒ Classmethod, Inc.
let names = users.map { user in
user.name
}
println(names)
実践 CollectionAPI
• Swiftのコードでfor文は一回も使わなかった
43Ⓒ Classmethod, Inc.
var names = [String]()
for user in users {
names.append(user.name)
}
println(names)
マッピングのたびに
コード領域に変数が
一つ加わる
変数という状態を
考えずに済む
let totalAge =
users.reduce(0) { total, user in
total + user.age
}
println(totalAge)
実践 CollectionAPI
• Swiftのコードでfor文は一回も使わなかった
44Ⓒ Classmethod, Inc.
var totalAge = 0
for user in users {
totalAge += user.age
}
println(totalAge)
集計の際に変数1つが
コード領域に加わる
集計の際に変数は
考えなくていい
実践 CollectionAPI
• コード量を大幅に削減できた
45Ⓒ Classmethod, Inc.
- (NSArray *)namesForUsers:(NSArray *)users
{
NSMutableArray *names = [NSMutableArray new];
for(User *user in users) {
[names addObject:user.name];
}
return [NSArray arrayWithArray:names];
}
のようなマッピング用のメソッド、処理がmap一つで書ける
実践 CollectionAPI
• メモリ管理のためにunownedやweakを使う
46Ⓒ Classmethod, Inc.
users.map { [weak self] user in
self?.names.append(user.name)
return Void()
}
• map等のクロージャでselfを使う場合は
 循環参照の可能性からweak, unownedを考慮する
• 設計を考え直す
47Ⓒ Classmethod, Inc.
関数フローを用い
コード領域から
できるだけ状態を排する
Collection API
• 実践 CollectionAPI
• map, filter, reduce
• flatMap(Swift 1.2)
48Ⓒ Classmethod, Inc.
map, filter, reduce
• map
49Ⓒ Classmethod, Inc.
Array<T> Array<U>
map(transform: T -> U)
T U
T
T
U
U
transform
map, filter, reduce
• filter
50Ⓒ Classmethod, Inc.
Array<T> Array<T>
filter(includeElement: T -> Bool)
T
T
T
true/false
T
T
includeElement
map, filter, reduce
• reduce
51Ⓒ Classmethod, Inc.
Array<T>
reduce(initial: U,
combine: (U, T) -> U)
T
combine
T
T
U
U
initial
map, filter, reduce
• 文字列の配列のうち、二文字以上のものを選び、
 文字数のトータルを集計する
52Ⓒ Classmethod, Inc.
Before
NSArray *strings = [@“aaaa”, @“bbb”, @“c”, @“dd”];
NSUInteger totalLengthForStrings = 0;
for(NSString *string in strings) {
NSUInteger lengthOfString = string.length
if (lengthOfString >= 2) {
totalLengthForStrings += lengthOfString
}
}
NSLog(@“%ld”, totalLengthForStrings) // 9
map, filter, reduce
• 文字列の配列のうち、二文字以上のものを選び、
 文字数のトータルを集計する
53Ⓒ Classmethod, Inc.
After
let strings = [“aaaa”, “bbb”, “c”, “dd”]
let totalCount =
strings.map(countElements)
.filter { count in count >= 2 }
.reduce(0, +)
println(totalCount) // 9
54Ⓒ Classmethod, Inc.
コレクションを
関数フローで
整形・選択・集計する
Collection API
• 実践 CollectionAPI
• map, filter, reduce,
sorted, first, last
• flatMap(Swift 1.2)
55Ⓒ Classmethod, Inc.
56Ⓒ Classmethod, Inc.
flatMap(Swift 1.2)
let strings = [“aaaa”, “bbb”]
let bothCaseStrings =
strings.flatMap { str in
[str.uppercaseString, str.lowercaseString]
}
println(bothCaseStrings)
// [“aaaa”, “AAAA”, “bbb”, “BBB”]
57Ⓒ Classmethod, Inc.
flatMap(Swift 1.2)
Array<T> Array<U>
flatMap(transform: T -> [U])
T U
transform
T
T
U
U
U
U
U
58Ⓒ Classmethod, Inc.
Topics for today
• Enum
• Collection API
• BrightFutures
59Ⓒ Classmethod, Inc.
BrightFuture
• Futures in Swift
• Future
• Promise
• メソッド概観
• Pluggable Activities
60Ⓒ Classmethod, Inc.
• Swiftz
https://github.com/typelift/swiftz
• BrightFutures
https://github.com/Thomvis/BrightFutures
61Ⓒ Classmethod, Inc.
Futures in Swift
• Swiftz
関数型プログラミングインターフェイスをSwiftに追加
62Ⓒ Classmethod, Inc.
Futures in Swift
• Swiftz
多くの演算子はHaskellやF#から由来している
中には • (Option+8) などの特殊文字もある
63Ⓒ Classmethod, Inc.
Futures in Swift
• Swiftz
非同期を扱う為のクラスFutureも
抽象度の高い基底クラスを有するため採用見送り
64Ⓒ Classmethod, Inc.
Futures in Swift
• Swiftz
非同期を扱う為のクラスFutureも
抽象度の高い基底クラスを有するため採用見送り
65Ⓒ Classmethod, Inc.
Futures in Swift
66Ⓒ Classmethod, Inc.
BrightFutures
BrightFuture
• Futures in Swift
• Future
• Promise
• メソッド概観
• Pluggable Activities
67Ⓒ Classmethod, Inc.
68
コールバックハンドラでの
非同期処理
69Ⓒ Classmethod, Inc.
Future
• Objective-Cでの典型的な非同期ハンドリング
[[SomeTaskManager sharedInstance]
taskWithCompletion:^(NSData *data, NSError *err) {
if (err) {
// エラーハンドリング
} else {
// エラーがない時の処理
}
}];
70Ⓒ Classmethod, Inc.
Future
• エラーハンドリングについてはほぼ定形の処理
• エラーが無い時に続けて簡単に処理を書きたい…
• 非同期処理がまたがる度にネストが深くなっていく
71Ⓒ Classmethod, Inc.
Future
• エラーハンドリングについてはほぼ定形の処理
• エラーが無い時に続けて簡単に処理を書きたい…
• 非同期処理がまたがる度にネストが深くなっていく
そのお悩み
Future<T>が
解決します!!!!
72Ⓒ Classmethod, Inc.
public class Future<T> {
var result: Result<T>? = nil
...
}
非同期処理エラーの可能性
を持った値
Future
public enum Result<T> {
case Success(Box<T>)
case Failure(NSError)
}
エラーの可能性
を持った値
Result<T>は実装に入っている
73Ⓒ Classmethod, Inc.
Future
Success
Failure
T
NSError
Pending None
Some(Result<T>)
• Futureの取りうる状態は3つ
非同期処理中
非同期処理完了
74Ⓒ Classmethod, Inc.
Future
• Futureをつくる
public func future<T>(
context c: ExecutionContext = Queue.global,
task: () -> T
) -> Future<T>
let futureValue = future {
// 何か重い処理
return 返り値
}
必要に応じてキューを指定する
(Queueはdispatch_queue_tのラッパー)
75
Futureは非同期エラーの
可能性をもった値
BrightFuture
• Futures in Swift
• Future
• Promise
• メソッド概観
• Pluggable Activities
76Ⓒ Classmethod, Inc.
77Ⓒ Classmethod, Inc.
Promise
• Future<T>の生成に利用
func someTask() -> Future<NSData> {
let promise = Promise<NSData>()
SomeTaskManager.sharedInstance
.taskWithCompletion { data, err in
if err != nil { // エラーハンドリング
promise.failure(err)
} else { // エラーがない時の処理
promise.success(data)
}
}
return promise.future
}
78Ⓒ Classmethod, Inc.
Promise
• 「約束」「契約」を表すオブジェクト
func someTask() -> Future<NSData> {
let promise = Promise<NSData>()
SomeTaskManager.sharedInstance
.taskWithCompletion { data, err in
if err != nil { // エラーハンドリング
promise.failure(err)
} else { // エラーがない時の処理
promise.success(data)
}
}
return promise.future
}
コールバックが一回きり呼ばれる
契約を表す
Futureをエラーで
完了させる
Futureを成功で
完了させる
79Ⓒ Classmethod, Inc.
Promise
• 非同期処理が呼ばれた証として
 Future<T>オブジェクトを発行
func someTask() -> Future<NSData> {
let promise = Promise<NSData>()
SomeTaskManager.sharedInstance
.taskWithCompletion { data, err in
if err != nil { // エラーハンドリング
promise.failure(err)
} else { // エラーがない時の処理
promise.success(data)
}
}
return promise.future
}
Futureを発行する
80Ⓒ Classmethod, Inc.
BoltsFramework
Promise
81Ⓒ Classmethod, Inc.
• BrightFutures と BoltsFrameworkの比較
- (BFTask *)someTask {
BFTaskCompletionSource *task =
[BFTaskCompletionSource taskCompletionSource];
[[SomeTaskManager sharedInstance]
taskWithCompletion:^(NSData *data, NSError *err) {
if (err) {
[task setError:err];
} else {
[task setResult:data];
}
}];
return task.task;
}
Promise
Sourseの生成
完了処理
BFTaskをSourceから生成
82Ⓒ Classmethod, Inc.
• BrightFutures と BoltsFrameworkの比較
func someTask() -> Future<NSData> {
let promise = Promise<NSData>()
SomeTaskManager.sharedInstance()
.taskWithCompletion { data, err in
if err != nil {
promise.failure(err)
} else {
promise.success(data)
}
}
return promise.future
}
Promise
Promiseの生成
完了処理
FutureをPromiseから生成
83Ⓒ Classmethod, Inc.
Promise
• Promiseは発行したら必ず成功かエラーを一回だけ
発行するように実装
• Promiseに複数の成功を送るとランタイムエラーを
起こす
• 複数回呼ばれるようなDelegateとは相性が悪い
84
コールバックハンドラには
Promiseを用いてFutureを生成
BrightFuture
• Futures in Swift
• Future
• Promise
• メソッド概観
• Pluggable Activities
85Ⓒ Classmethod, Inc.
86Ⓒ Classmethod, Inc.
メソッド概観
• onComplete in Future<T>
onComplete(
callback: Result<T> -> Void
) -> Future<T>
T
NSError
None
Result<T>
callback
Future<T>
87Ⓒ Classmethod, Inc.
メソッド概観
futureTask.onComplete { result in
switch result {
case .Success(let val): ()
case .Failure(let err): ()
}
}
非同期計算の結果にかかわらす
Result<T> を返却
• onComplete in Future<T>
88Ⓒ Classmethod, Inc.
メソッド概観
• onSuccess in Future<T>
onSuccess(
callback: T -> Void
) -> Future<T>
T
NSError
None
Result<T>
callback
Future<T>
89Ⓒ Classmethod, Inc.
メソッド概観
• onSuccess in Future<T>
futureTask.onSuccess { value in
// T型のvalueに対する処理
}
非同期計算が成功した場合
Tを返却
90Ⓒ Classmethod, Inc.
メソッド概観
• onFailure in Future<T>
onFailure(
callback: NSError -> Void
) -> Future<T>
T
NSError
None
Result<T>
Future<T>
callback
91Ⓒ Classmethod, Inc.
メソッド概観
futureTask.onFailure { error in
// NSError型のerrorに対する処理
}
非同期計算が成功した場合
NSError を返却
• onFailure in Future<T>
92Ⓒ Classmethod, Inc.
メソッド概観
• map in Future<T>
Future<T> Future<U>
map(f: T -> U)
T
NSError
U
NSError
f
None
93Ⓒ Classmethod, Inc.
// 非同期エラーの可能性をもった値を
let futureData =
someTask() // Future<NSData>型の返り値
// 非同期エラーの可能性を保ったまま中身だけ変更
futureData.map { data in
NSString(
data: data,
encoding: NSUTF8StringEncoding
)
} // Future<NSString>型の返り値
メソッド概観
• map in Future<T>
94Ⓒ Classmethod, Inc.
メソッド概観
• flatMap in Future<T>
Future<T> Future<U>
flatMap(f: T -> Future<U>)
T
NSError
U
NSError
f
None
95Ⓒ Classmethod, Inc.
// 非同期エラーの可能性をもった値を
let someURLString =
someURLTask()// Future<String>型の返り値
// 中身がエラーでなければ続きの
// 非同期エラー可能性をもった値を評価
someURLString.flatMap(fetchData)
// fetchData: Stringを引数にもち
// Future<NSData>を返り値に持つ関数
メソッド概観
• flatMap in Future<T>
96
非同期処理を定形的な
ハンドリングで記述
BrightFuture
• Futures in Swift
• Future
• Promise
• メソッド概観
• Pluggable Activities
97Ⓒ Classmethod, Inc.
• 非同期処理のまとまり毎にFutureを生成
98Ⓒ Classmethod, Inc.
Pluggable Activities
→非同期処理同士を抜き差し、順序入替しやすくなった
Web API Task App DB Task
Web API TaskApp DB Task
• 非同期処理のまとまり毎にFutureを生成
99Ⓒ Classmethod, Inc.
Pluggable Activities
Web API App DB HeavyTaskInfrastructure
Use case Authentication UserLogic
→ロジックが
  非同期を要する処理かどうかがわかりやすくなった
→アクティビティ図とコードが対応するようになった
100Ⓒ Classmethod, Inc.
Pluggable Activities
User Event
API Call
DB Update
NSError NSError Success
• 非同期処理のまとまり毎にFutureを生成
101
Futureでアカルイ
非同期処理
102Ⓒ Classmethod, Inc.
103
おまけ
Topics for today
• Enum
• Collection API
• BrightFutures
104Ⓒ Classmethod, Inc.
Topics for today
• Enum
• Collection API
• BrightFutures
105Ⓒ Classmethod, Inc.
Optional<T>
Result<T>
Array<T>
Future<T>
106
• Enum
• Collection API
• BrightFutures
107Ⓒ Classmethod, Inc.
Optional<T>
Result<T>
Array<T>
Future<T>
map
map(f: T -> U) -> U?
map(f: T -> U) -> Result<U>
map(f: T -> U) -> Array<U>
map(f: T -> U) -> Future<U>
• Enum
• Collection API
• BrightFutures
108Ⓒ Classmethod, Inc.
flatMap
Optional<T>
Result<T>
Array<T>
Future<T>
flatMap(f: T -> U?) -> U?
flatMap(f: T -> Result<U>)
-> Result<U>
flatMap(f: T -> Array<U>)
-> Array<U>
flatMap(f: T -> Future<U>)
-> Future<U>
109Ⓒ Classmethod, Inc.
map ・ flatMapを
適用できる型を抽象化
XXX<T> map(f: T -> U) -> XXX<U>
flatMap(f: T -> XXX<U>)
-> XXX<U>
Functor・Applicative・Monadへ
110
111Ⓒ Classmethod, Inc.
Haskell・Scala等の
先達に根拠を求める
112Ⓒ Classmethod, Inc.
巨人の肩に乗る
Developer Day
スライドは後日ブログで公開します。
113
A-1
Ⓒ Classmethod, Inc.
#cmdevio2015

More Related Content

続・ゲンバのSwift

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy