Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
potatotips #36: Translatorのススメ
Search
Takeshi Ihara
January 17, 2017
Programming
560
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
potatotips #36: Translatorのススメ
potatotips #36
https://potatotips.connpass.com/event/46832/
Takeshi Ihara
January 17, 2017
More Decks by Takeshi Ihara
See All by Takeshi Ihara
iOSDC20200921: Feature Flagを適切に分類することでA/Bテストの運用コストを下げる
nonchalant
3
1.4k
iOSDC 20190906: 動画アプリの投げ銭機能における 消耗型課金の仕組みと実装
nonchalant
3
6.4k
iOSDC 20190906: 動画アプリの投げ銭機能における 消耗型課金の仕組みと実装 with 発表ノート
nonchalant
2
640
Sign In with Apple
nonchalant
1
2.4k
iOSDC RejectCon 20180915: Factoryの自動生成によりテストを書きやすくする
nonchalant
1
750
iOSDC 20180902: 小さくはじめる端末管理
nonchalant
2
1k
devsap 20180728: コード生成のススメ
nonchalant
0
140
potatotips #50: iOSは自動生成の夢を見るか?
nonchalant
0
2k
try! Swift Tokyo 2018: Best Docker Container in Swift
nonchalant
1
1.4k
Other Decks in Programming
See All in Programming
人間の目はかわらない、だからJPEGは30年もつ
yuzneri
12
18k
【やさしく解説 設計編・中級 #4】ルールの寿命と、システムの年輪
panda728
PRO
2
180
ドリフトを絶対に許さない(?)CDK運用 / CDK Ops with Zero Tolerance for Drifts (?)
akihisaikeda
1
180
S3 を使うアプリケーションをローカル完結で動かすことに全力を注いでみた / Running S3 Apps Offline
contour_gara
0
420
【やさしく解説 設計編・中級 #1】一つの車に、運転手は一人 ~ある倉庫システムの事例から~
panda728
PRO
0
210
琵琶湖の水は止められてもNet--HTTPのリトライは止められない / You might be able to stop the water flow of Lake Biwa but you can't stop Net::HTTP retries
luccafort
PRO
0
640
AWS DevOps AgentのAzure接続機能を検証して見えた活用法/Use Cases Verified for the AWS DevOps Agent's Azure Connectivity Feature
masakiokuda
1
230
全PRの83%がAIレビューだけでマージできるようになった開発組織はその後どうなったか
athug
1
1.5k
進化を続けるGo toolsの現在地 / The Current State of Ever-Evolving Go Tools
hond0413
0
190
生成AIで帳票OCRが「簡単に」作れる時代になった?
kon_shou
0
710
今さら聞けない .NET CLI
htkym
0
190
わからない話を追いかけたら、プログラミング言語を作る側にいた
ydah
3
490
Featured
See All Featured
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
2.1k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.9k
Designing Experiences People Love
moore
143
24k
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
360
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4.5k
Building Adaptive Systems
keathley
44
3.2k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
232
55k
Reality Check: Gamification 10 Years Later
codingconduct
0
2.2k
Rails Girls Zürich Keynote
gr2m
96
14k
Being A Developer After 40
akosma
91
590k
How to Talk to Developers About Accessibility
jct
2
500
Everyday Curiosity
cassininazir
0
270
Transcript
Translatorͷεεϝ potatotips #36 / @nonchalant0303
Profile • Takeshi Ihara / @nonchalant0303 • Recruit Marketing Partners
• iOS Engineer
Translator • UseCaseͰऔಘͨ͠EntityΛPresentationͷ ͨΊͷModelʹม͢Δ 1SFTFOUBUJPO %PNBJO *OGSBTUSVDUVSF 6TF$BTF 5SBOTMBUPS 7JFX.PEFM
Entity w/o Translator struct Entity { let title: String let
description: String let imageUrl: URL let rank: Rank init(title: String, description: String, imageUrl: String, rank: Int) { self.title = title self.description = description self.imageUrl = URL(string: imageUrl)! self.rank = Rank(rank: rank) } }
Entity w/o Translator struct Entity { let title: String let
description: String let imageUrl: URL let rank: Rank init(title: String, description: String, imageUrl: String, rank: Int) { self.title = title self.description = description self.imageUrl = URL(string: imageUrl)! self.rank = Rank(rank: rank) } } *OJUJBMJ[FSʹ มϩδοΫؚ͕·ΕͯΔ
ผʹ͍͍ͷͰʁ
ͨͱ͑… import Foundation struct Entity { let property1: String let
property2: Float ... let property15: [String] init(property1: Int, property2: Int, property15: [Int]) { self.property1 = "\(property1)ԁ" self.property2 = Float(property2) * 1.08 ... self.property15 = property15.map { "\($0)ԁ" } } }
ͨͱ͑… import Foundation struct Entity { let property1: String let
property2: Float ... let property15: [String] init(property1: Int, property2: Int, property15: [Int]) { self.property1 = "\(property1)ԁ" self.property2 = Float(property2) * 1.08 ... self.property15 = property15.map { "\($0)ԁ" } } } ཁૉ͕૿͑Δͱ มϩδοΫ͕ංେԽ͕ͪ͠
class TableViewCell: UITableViewCell { @IBOutlet private weak var label1: UILabel!
@IBOutlet private weak var label2: UILabel! ... @IBOutlet private weak var label15: UILabel! func configure(entity: Entity) { label1.text = "\(entity.property1)ԁ" label2.text = "\(Float(entity.property2) * 1.08)" ... label15.text = entity.property15.map { "\($0)ԁ" }.reduce("") { $0 != "" ? "\($0), \($1)" : "\($1)" } } } 1. Translate in View
class TableViewCell: UITableViewCell { @IBOutlet private weak var label1: UILabel!
@IBOutlet private weak var label2: UILabel! ... @IBOutlet private weak var label15: UILabel! func configure(entity: Entity) { label1.text = "\(entity.property1)ԁ" label2.text = "\(Float(entity.property2) * 1.08)" ... label15.text = entity.property15.map { "\($0)ԁ" }.reduce("") { $0 != "" ? "\($0), \($1)" : "\($1)" } } } 1. Translate in View 7JFXʹϩδοΫ͕ છΈग़ͯ͠Δ
struct Entity { let property1: String let property2: Int ...
let property15: [String] } struct ViewModel { let property1: String let property2: String ... let property15: String } class Translator { static func translate(entity: Entity) -> ViewModel { return ViewModel( property1: "\(entity.property1)ԁ", property2: "\(Float(entity.property2) * 1.08)", ... property15: entity.property15.map { "\($0)ԁ" }.reduce("") { $0 != "" ? "\($0), \($1)" : "\($1)" } ) } } 2. Translator
struct Entity { let property1: String let property2: Int ...
let property15: [String] } struct ViewModel { let property1: String let property2: String ... let property15: String } class Translator { static func translate(entity: Entity) -> ViewModel { return ViewModel( property1: "\(entity.property1)ԁ", property2: "\(Float(entity.property2) * 1.08)", ... property15: entity.property15.map { "\($0)ԁ" }.reduce("") { $0 != "" ? "\($0), \($1)" : "\($1)" } ) } } 2. Translater 1SFTFOUBUJPOͷͨΊͷ .PEFMΛ༻ҙ͢Δ 5SBOTMBUPS
2. Translator class Repository { func findAll() -> [Entity] {
return ... } } class UseCase { let repository: Repository init(repository: Repository) { self.repository = repository } func getAll() -> [ViewModel] { return repository.findAll().map { Translator.translate(entity: $0) } } } UseCaseͰऔಘͨ͠EntityΛPresentationͷͨΊͷModelʹม͢Δ
2. Translater class Repository { func findAll() -> [Entity] {
return ... } } class UseCase { let repository: Repository init(repository: Repository) { self.repository = repository } func getAll() -> [ViewModel] { return repository.findAll().map { Translator.translate(entity: $0) } } } UseCaseͰऔಘͨ͠EntityΛPresentationͷͨΊͷModelʹม͢Δ &OUJUZΛ.PEFMʹม͢Δ
View, Entity͔Β มϩδοΫΛͰ͖ͨʂ
Pros/Cons of Translator • Pros • มϩδοΫΛͰ͖Δ • Cons •
ʹͳΓ͔Ͷͳ͍
ඞཁʹԠͯ͡TranslatorΛ ಋೖ͠Α͏ʂ
Translator͕༗ޮͩͱࢥ͏ྫ • UITableViewʹ දࣔ͢ΔΞΠςϜ͕ ʮEntityͷ+1ʯ
ViewController w/o Translator class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { private
let tableView = UITableView(frame: UIScreen.main.bounds) var todos: [Todo] = [] // Entity override func viewDidLoad() { ... } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return todos.count + 1 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell() if indexPath.row < todos.count { cell.textLabel?.text = todos[indexPath.row].title } else { cell.textLabel?.text = "+ Ճ͢Δ" cell.textLabel?.textColor = .gray } return cell } }
ViewController w/o Translator class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { private
let tableView = UITableView(frame: UIScreen.main.bounds) var todos: [Todo] = [] // Entity override func viewDidLoad() { ... } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return todos.count + 1 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell() if indexPath.row < todos.count { cell.textLabel?.text = todos[indexPath.row].title } else { cell.textLabel?.text = "+ Ճ͢Δ" cell.textLabel?.textColor = .gray } return cell } } *OEFY1BUIͰཧͯͯ͠πϥΠ 3VOUJNFFSSPSͷϦεΫ
Translate from Entity to Model protocol Translator { associatedtype Entity
associatedtype Model static func translate(entity: Entity) -> Model } struct Todo { let title: String } enum Item { case todo(title: String) case add(title: String) } class TodoTranslator: Translator { typealias Entity = [Todo] typealias ViewModel = [Item] static func translate(entity: Entity) -> ViewModel { return Array( [ entity.map { Item.todo(title: $0.title) }, [ Item.add(title: "+ Ճ͢Δ") ] ].joined() ) } }
Translate from Entity to Model protocol Translator { associatedtype Entity
associatedtype Model static func translate(entity: Entity) -> Model } struct Todo { let title: String } enum Item { case todo(title: String) case add(title: String) } class TodoTranslator: Translator { typealias Entity = [Todo] typealias ViewModel = [Item] static func translate(entity: Entity) -> ViewModel { return Array( [ entity.map { Item.todo(title: $0.title) }, [ Item.add(title: "+ Ճ͢Δ") ] ].joined() ) } } $FMM༻ͷ.PEFM 5BCMF7JFXදࣔ͢Δ ΞΠςϜΛͯ͢༻ҙ
ViewController w/ Translator class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { private
let tableView = UITableView(frame: UIScreen.main.bounds) var items: [Item] = [] // Model override func viewDidLoad() { ... } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return items.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell() switch items[indexPath.row] { case .todo(let title): cell.textLabel?.text = title case .add(let title): cell.textLabel?.text = title cell.textLabel?.textColor = .gray } return cell } }
ViewController w/ Translator class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { private
let tableView = UITableView(frame: UIScreen.main.bounds) var items: [Item] = [] // Model override func viewDidLoad() { ... } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return items.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell() switch items[indexPath.row] { case .todo(let title): cell.textLabel?.text = title case .add(let title): cell.textLabel?.text = title cell.textLabel?.textColor = .gray } return cell } } ܕͰཧ͞ΕͯΔͷͰ ҆શʂ
͋Γ͕ͱ͏͍͟͝·ͨ͠