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.3k
iOSDC 20190906: 動画アプリの投げ銭機能における 消耗型課金の仕組みと実装 with 発表ノート
nonchalant
2
630
Sign In with Apple
nonchalant
1
2.4k
iOSDC RejectCon 20180915: Factoryの自動生成によりテストを書きやすくする
nonchalant
1
740
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
ADKを使って簡単にAIエージェントを作ってみよう
k1mu21
0
250
その問い、本当に正しいですか?AI時代のエンジニアに必要な哲学と認知科学 / ai-philosophy-cognitive-science
minodriven
5
3.9k
A2UI という光を覗いてみる
satohjohn
1
130
The Arts and Crafts of Work in the AI Era — Toward Mastery in Software Development
kuranuki
1
750
These Five Tricks Can Make Your Apps Greener, Cheaper, & Nicer
hollycummins
0
280
DynamoDBには集計系のクエリがないけどなんとかしたい
musan
1
130
Semantic Version 単位で戦略を柔軟に変えて、パッケージアップデートを自動化する
daitasu
0
210
ECSアプリログをFireLensでコスト削減しようとしたけど諦めた話 in Fargate×Node.js
akihisaikeda
2
4k
AI 時代のソフトウェア設計の学び方
masuda220
PRO
29
12k
Developing with AI Agents — Codex, Claude Code & Cowork Practical Guide
x5gtrn
PRO
0
1.2k
肥大化するレガシーコードに立ち向かうためのインターフェース分離と依存の逆転 / JJUG CCC 2026 Spring
hirokunimaeta
0
530
New "Type" system on PicoRuby
pocke
1
810
Featured
See All Featured
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
200
Building Applications with DynamoDB
mza
96
7.1k
Claude Code のすすめ
schroneko
67
230k
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
250
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
1
250
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
<Decoding/> the Language of Devs - We Love SEO 2024
nikkihalliwell
1
240
We Have a Design System, Now What?
morganepeng
55
8.2k
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
118
120k
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
570
GraphQLの誤解/rethinking-graphql
sonatard
75
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 } } ܕͰཧ͞ΕͯΔͷͰ ҆શʂ
͋Γ͕ͱ͏͍͟͝·ͨ͠