Сергей Крапивенский
Transcript of Сергей Крапивенский
![Page 1: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/1.jpg)
Кто подставил Барбару Лисков?
Сергей Крапивенский, Rambler&Co
или Кто кого SOLID?
![Page 2: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/2.jpg)
“Do Not Learn Frameworks”
![Page 3: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/3.jpg)
Фундаментальные знания
![Page 4: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/4.jpg)
Фундаментальные знания
Язык
![Page 5: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/5.jpg)
Фундаментальные знания
Язык
Фреймворки
![Page 6: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/6.jpg)
Фундаментальные знания
Язык
Фреймворки
![Page 7: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/7.jpg)
RayWenderlich - driven development
Senior ReactiveCocoa Developer
Рамблер - секта VIPER
![Page 8: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/8.jpg)
Фундаментальные знания
Язык
Фреймворки
![Page 9: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/9.jpg)
Фундаментальные знания
Язык
Фреймворки
![Page 10: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/10.jpg)
Фундаментальные знания
Язык
Фреймворки
![Page 11: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/11.jpg)
Фундаментальные знания• Структуры данных
• Алгоритмы
• Паттерны
• DRY, KISS, YAGNI
• SOLID
• И многое другое
![Page 12: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/12.jpg)
![Page 13: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/13.jpg)
Single responsibility principle
Open-closed principle
Liskov substitution principle
Interface segregation principle
Dependency inversion principle
![Page 14: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/14.jpg)
Single Responsibility Principle
“A class should have only one reason to change”
![Page 15: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/15.jpg)
MassiveViewController
1.Ответственности сильно связаны
2.Класс перестает помещаться в голове
3.Тяжело поддерживать и тестировать
![Page 16: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/16.jpg)
UITableViewController
1.Изменение логики работы с таблицей
2.Поменять иерархию вьюшек
![Page 17: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/17.jpg)
UITableViewController
Решение проблемы: не использовать его
![Page 18: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/18.jpg)
Запуск приложения
Push Notifications
Quick Actions
Уведомления о
состояниях приложенияОткрытие по URL
Фоновая
загрузка данных
AppDelegate
![Page 19: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/19.jpg)
AppDelegate
Запуск приложения Quick Actions
ПоискPush Notifications
Открытие URLСостояния приложения
Загрузка в фоне
Handoff
Extensions
![Page 20: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/20.jpg)
AppDelegate
Запуск приложения Quick Actions
ПоискPush Notifications
Открытие URLСостояния приложения
Загрузка в фоне
Handoff
Extensions
https://github.com/rambler-digital-solutions/RamblerAppDelegateProxy
![Page 21: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/21.jpg)
SRP о снижении сложности
![Page 22: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/22.jpg)
Single responsibility principle
Open-closed principle
Liskov substitution principle
Interface segregation principle
Dependency inversion principle
![Page 23: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/23.jpg)
Open-Closed Principle
“Software entities (classes, modules, functions, etc.) should be open for extension, but closed for
modification”
![Page 24: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/24.jpg)
Простой и устойчивый дизайн
![Page 25: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/25.jpg)
Новость
Новость
Новость
Новость
![Page 26: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/26.jpg)
Новость
Новость
Новость
Новость
Новость с фото
Новость с фото
![Page 27: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/27.jpg)
Новость
Новость
Новость
Новость
Новость с фото
Новость с фото
Реклама
Реклама
![Page 28: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/28.jpg)
} else ... return cell }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SomeIdentifier")! as UITableViewCell
let model = self.models[indexPath.row]
if (model is News) { let newsCell: NewsCell? = (cell as? NewsCell) newsCell?.setup(withNews: model as! News) } else if (model is Advertisement) { let adCell: AdvertisementCell? = (cell as? AdvertisementCell) adCell?.setup(withAd: model as! Advertisement)
![Page 29: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/29.jpg)
} else ... return cell }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SomeIdentifier")! as UITableViewCell
let model = self.models[indexPath.row]
if (model is News) { let newsCell: NewsCell? = (cell as? NewsCell) newsCell?.setup(withNews: model as! News) } else if (model is Advertisement) { let adCell: AdvertisementCell? = (cell as? AdvertisementCell) adCell?.setup(withAd: model as! Advertisement)
![Page 30: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/30.jpg)
} else ... return cell }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SomeIdentifier")! as UITableViewCell
let model = self.models[indexPath.row]
if (model is News) { let newsCell: NewsCell? = (cell as? NewsCell) newsCell?.setup(withNews: model as! News) } else if (model is Advertisement) { let adCell: AdvertisementCell? = (cell as? AdvertisementCell) adCell?.setup(withAd: model as! Advertisement)
![Page 31: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/31.jpg)
} else ... return cell }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SomeIdentifier")! as UITableViewCell
let model = self.models[indexPath.row]
if (model is News) { let newsCell: NewsCell? = (cell as? NewsCell) newsCell?.setup(withNews: model as! News) } else if (model is Advertisement) { let adCell: AdvertisementCell? = (cell as? AdvertisementCell) adCell?.setup(withAd: model as! Advertisement)
![Page 32: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/32.jpg)
} else ... return cell }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SomeIdentifier")! as UITableViewCell
let model = self.models[indexPath.row]
if (model is News) { let newsCell: NewsCell? = (cell as? NewsCell) newsCell?.setup(withNews: model as! News) } else if (model is Advertisement) { let adCell: AdvertisementCell? = (cell as? AdvertisementCell) adCell?.setup(withAd: model as! Advertisement)
![Page 33: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/33.jpg)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let model: CellObject = self.models[indexPath.row] as! CellObject let cell = tableView.dequeueReusableCell(withIdentifier: "CellIdentifier")! as! ConfigurableCell cell.configure(withObject: model) return cell as! UITableViewCell }
![Page 34: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/34.jpg)
NewsCell PhotoCell AdCell
<ConfigurableCell>
func configure(withObject: CellObject)
News Photo Advert
<CellObject>
func cellClass() -> AnyClass
![Page 35: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/35.jpg)
Когда применять?
![Page 36: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/36.jpg)
![Page 37: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/37.jpg)
Single responsibility principle
Open-closed principle
Liskov substitution principle
Interface segregation principle
Dependency inversion principle
![Page 38: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/38.jpg)
![Page 39: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/39.jpg)
Liskov Substitution Principle
“Subtypes must be substitutable for their base types”
![Page 40: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/40.jpg)
Нужен для проверки корректности наследования
![Page 41: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/41.jpg)
func hideViews() { UIView.animate(withDuration: 1.0, animations: { for view in self.animatableViews { view.alpha = 0.5 } }) }
![Page 42: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/42.jpg)
UIView
UIVisualEffectView
Всё ок !
<UIVisualEffectView> is being asked to animate its opacity. This will cause the effect to appear broken until
opacity returns to 1
![Page 43: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/43.jpg)
¯\_(ツ)_/¯
![Page 44: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/44.jpg)
Single responsibility principle
Open-closed principle
Liskov substitution principle
Interface segregation principle
Dependency inversion principle
![Page 45: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/45.jpg)
Interface Segregation Principle
“Clients should not be forced to depend on methods that they
do not use”
![Page 46: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/46.jpg)
MailAPIClient
- auth- findContact- getMailboxes- createMailbox- sendMailAuth Contacts Mailboxes Messages
- auth- findContact- getMailboxes- createMailbox- sendMail
- auth- findContact- getMailboxes- createMailbox- sendMail
- auth- findContact- getMailboxes- createMailbox- sendMail
- auth- findContact- getMailboxes- createMailbox- sendMail
![Page 47: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/47.jpg)
AuthServiceMailboxServiceContactServiceMessageService
Auth Contacts Mailboxes Messages
- auth- findContact- getMailboxes- createMailbox- sendMail
- auth- findContact- getMailboxes- createMailbox- sendMail
- auth- findContact- getMailboxes- createMailbox- sendMail
- auth- findContact- getMailboxes- createMailbox- sendMail
MailAPIClient
![Page 48: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/48.jpg)
ISP - это не SRP
![Page 49: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/49.jpg)
- sendSelfDestructMessage- deleteBothMessages
ChatChannel
- loadMessages- sendMessage- replyToMessage- forwardMessage
ChannelSecretChat Supergroup
- banUser
Group
- loadMessages- sendMessage- replyToMessage- forwardMessage- sendSelfDestruct- deleteBoth- pinMessage- banUser
- pinMessage - loadMessages- sendMessage- replyToMessage- forwardMessage- sendSelfDestruct- deleteBoth- pinMessage- banUser
- loadMessages- sendMessage- replyToMessage- forwardMessage- sendSelfDestruct- deleteBoth- pinMessage- banUser
- loadMessages- sendMessage- replyToMessage- forwardMessage- sendSelfDestruct- deleteBoth- pinMessage- banUser
![Page 50: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/50.jpg)
Single responsibility principle
Open-closed principle
Liskov substitution principle
Interface segregation principle
Dependency inversion principle
![Page 51: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/51.jpg)
Dependency Inversion Principle
“A. High-level modules should not depend on low-level modules. Both
should depend on abstractions”
![Page 52: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/52.jpg)
Dependency Inversion Principle
“B. Abstractions should not depend on details. Details should depend
on abstractions”
![Page 53: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/53.jpg)
func displayNews() { let newsPredicate = NSPredicate(...) let filteredNews = News.findAll() as! [News] // Отображаем новости }
Зависимость от Core Data
![Page 54: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/54.jpg)
NewsViewController MagicalRecord
Realm😓
![Page 55: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/55.jpg)
protocol NewsProvider { func obtainNewsForDate(date: NSDate) -> [News] }
Зависимость от Core Data
func displayNews() { let date = NSDate.init() let filteredNews = self.newsProvider?.obtainNewsForDate(date: date) // Отображаем новости }
![Page 56: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/56.jpg)
protocol NewsProvider { func obtainNewsForDate(date: NSDate) -> [News] }
Зависимость от Core Data
func displayNews() { let date = NSDate.init() let filteredNews = self.newsProvider?.obtainNewsForDate(date: date) // Отображаем новости }
![Page 57: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/57.jpg)
class ViewController: UIViewController { init(newsProvider : NewsProvider) { self.newsProvider = newsProvider super.init(nibName: "ViewController", bundle: nil) }
}
Зависимость от Core Data
![Page 58: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/58.jpg)
NewsViewController <NewsProvider>
MagicalRecord NewsProvider
![Page 59: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/59.jpg)
Зависимости инвертированы #
![Page 60: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/60.jpg)
Серебряной пули нет 😢
![Page 61: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/61.jpg)
- Оноре де Бальзак
“Обстоятельства переменчивы, принципы - никогда”
![Page 62: Сергей Крапивенский](https://reader031.fdocument.pub/reader031/viewer/2022022413/58ed4c601a28aba04d8b46f1/html5/thumbnails/62.jpg)
Спасибо!
serkrapiv
sergey.krapivenskiy
rambler-ios