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
630
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
使用 Meilisearch 建立新聞搜尋工具
johnroyer
0
150
ランチタイムLT会3周年!ランチタイムLT会を3年間続けられたお話
y0hgi
1
140
Even G2とAWSで推しのエージェントを召喚しよう!
har1101
1
170
AI駆動開発を妨げる技術的負債の解消アプローチ / ai-refactoring-approach
minodriven
17
9k
OS アップデート対応の取り組み方がもっと共有されてほしい
andpad
0
110
地域 SRE コミュニティ最前線 - ホンマでっかSRE勉強会
tk3fftk
0
230
そのテスト、説明できますか?~LWテスト戦略FW~のご紹介
nakahara
0
200
Prismを使った型安全な暗号化_関数型まつり2026
_fhhmm
0
130
フィードバックで育てるAI開発
kotaminato
1
110
気圧・高度・GPSを記録&可視化するアプリ「Koudo」を作った話
hjmkth
1
350
分散システム、なんですぐ死んでしまうん?耐障害性を高めたいあなたのためのレジリエンスパターン入門
mshibuya
7
5.9k
AI 輔助遺留系統現代化的經驗分享
jame2408
1
1.2k
Featured
See All Featured
Ruling the World: When Life Gets Gamed
codingconduct
0
280
We Are The Robots
honzajavorek
0
280
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
260
Thoughts on Productivity
jonyablonski
76
5.2k
What's in a price? How to price your products and services
michaelherold
247
13k
The #1 spot is gone: here's how to win anyway
tamaranovitovic
3
1.1k
Odyssey Design
rkendrick25
PRO
2
730
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
210
Faster Mobile Websites
deanohume
310
32k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.3k
The World Runs on Bad Software
bkeepers
PRO
72
12k
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 } } ܕͰཧ͞ΕͯΔͷͰ ҆શʂ
͋Γ͕ͱ͏͍͟͝·ͨ͠