62
Кто подставил Барбару Лисков? Сергей Крапивенский, Rambler&Co или Кто кого SOLID?

Сергей Крапивенский

Embed Size (px)

Citation preview

Page 1: Сергей Крапивенский

Кто подставил Барбару Лисков?

Сергей Крапивенский, Rambler&Co

или Кто кого SOLID?

Page 2: Сергей Крапивенский

“Do Not Learn Frameworks”

Page 3: Сергей Крапивенский

Фундаментальные знания

Page 4: Сергей Крапивенский

Фундаментальные знания

Язык

Page 5: Сергей Крапивенский

Фундаментальные знания

Язык

Фреймворки

Page 6: Сергей Крапивенский

Фундаментальные знания

Язык

Фреймворки

Page 7: Сергей Крапивенский

RayWenderlich - driven development

Senior ReactiveCocoa Developer

Рамблер - секта VIPER

Page 8: Сергей Крапивенский

Фундаментальные знания

Язык

Фреймворки

Page 9: Сергей Крапивенский

Фундаментальные знания

Язык

Фреймворки

Page 10: Сергей Крапивенский

Фундаментальные знания

Язык

Фреймворки

Page 11: Сергей Крапивенский

Фундаментальные знания• Структуры данных

• Алгоритмы

• Паттерны

• DRY, KISS, YAGNI

• SOLID

• И многое другое

Page 12: Сергей Крапивенский
Page 13: Сергей Крапивенский

Single responsibility principle

Open-closed principle

Liskov substitution principle

Interface segregation principle

Dependency inversion principle

Page 14: Сергей Крапивенский

Single Responsibility Principle

“A class should have only one reason to change”

Page 15: Сергей Крапивенский

MassiveViewController

1.Ответственности сильно связаны

2.Класс перестает помещаться в голове

3.Тяжело поддерживать и тестировать

Page 16: Сергей Крапивенский

UITableViewController

1.Изменение логики работы с таблицей

2.Поменять иерархию вьюшек

Page 17: Сергей Крапивенский

UITableViewController

Решение проблемы: не использовать его

Page 18: Сергей Крапивенский

Запуск приложения

Push Notifications

Quick Actions

Уведомления о

состояниях приложенияОткрытие по URL

Фоновая

загрузка данных

AppDelegate

Page 19: Сергей Крапивенский

AppDelegate

Запуск приложения Quick Actions

ПоискPush Notifications

Открытие URLСостояния приложения

Загрузка в фоне

Handoff

Extensions

Page 20: Сергей Крапивенский

AppDelegate

Запуск приложения Quick Actions

ПоискPush Notifications

Открытие URLСостояния приложения

Загрузка в фоне

Handoff

Extensions

https://github.com/rambler-digital-solutions/RamblerAppDelegateProxy

Page 21: Сергей Крапивенский

SRP о снижении сложности

Page 22: Сергей Крапивенский

Single responsibility principle

Open-closed principle

Liskov substitution principle

Interface segregation principle

Dependency inversion principle

Page 23: Сергей Крапивенский

Open-Closed Principle

“Software entities (classes, modules, functions, etc.) should be open for extension, but closed for

modification”

Page 24: Сергей Крапивенский

Простой и устойчивый дизайн

Page 25: Сергей Крапивенский

Новость

Новость

Новость

Новость

Page 26: Сергей Крапивенский

Новость

Новость

Новость

Новость

Новость с фото

Новость с фото

Page 27: Сергей Крапивенский

Новость

Новость

Новость

Новость

Новость с фото

Новость с фото

Реклама

Реклама

Page 28: Сергей Крапивенский

} 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: Сергей Крапивенский

} 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: Сергей Крапивенский

} 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: Сергей Крапивенский

} 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: Сергей Крапивенский

} 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: Сергей Крапивенский

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: Сергей Крапивенский

NewsCell PhotoCell AdCell

<ConfigurableCell>

func configure(withObject: CellObject)

News Photo Advert

<CellObject>

func cellClass() -> AnyClass

Page 35: Сергей Крапивенский

Когда применять?

Page 36: Сергей Крапивенский
Page 37: Сергей Крапивенский

Single responsibility principle

Open-closed principle

Liskov substitution principle

Interface segregation principle

Dependency inversion principle

Page 38: Сергей Крапивенский
Page 39: Сергей Крапивенский

Liskov Substitution Principle

“Subtypes must be substitutable for their base types”

Page 40: Сергей Крапивенский

Нужен для проверки корректности наследования

Page 41: Сергей Крапивенский

func hideViews() { UIView.animate(withDuration: 1.0, animations: { for view in self.animatableViews { view.alpha = 0.5 } }) }

Page 42: Сергей Крапивенский

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: Сергей Крапивенский

¯\_(ツ)_/¯

Page 44: Сергей Крапивенский

Single responsibility principle

Open-closed principle

Liskov substitution principle

Interface segregation principle

Dependency inversion principle

Page 45: Сергей Крапивенский

Interface Segregation Principle

“Clients should not be forced to depend on methods that they

do not use”

Page 46: Сергей Крапивенский

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: Сергей Крапивенский

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: Сергей Крапивенский

ISP - это не SRP

Page 49: Сергей Крапивенский

- 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: Сергей Крапивенский

Single responsibility principle

Open-closed principle

Liskov substitution principle

Interface segregation principle

Dependency inversion principle

Page 51: Сергей Крапивенский

Dependency Inversion Principle

“A. High-level modules should not depend on low-level modules. Both

should depend on abstractions”

Page 52: Сергей Крапивенский

Dependency Inversion Principle

“B. Abstractions should not depend on details. Details should depend

on abstractions”

Page 53: Сергей Крапивенский

func displayNews() { let newsPredicate = NSPredicate(...) let filteredNews = News.findAll() as! [News] // Отображаем новости }

Зависимость от Core Data

Page 54: Сергей Крапивенский

NewsViewController MagicalRecord

Realm😓

Page 55: Сергей Крапивенский

protocol NewsProvider { func obtainNewsForDate(date: NSDate) -> [News] }

Зависимость от Core Data

func displayNews() { let date = NSDate.init() let filteredNews = self.newsProvider?.obtainNewsForDate(date: date) // Отображаем новости }

Page 56: Сергей Крапивенский

protocol NewsProvider { func obtainNewsForDate(date: NSDate) -> [News] }

Зависимость от Core Data

func displayNews() { let date = NSDate.init() let filteredNews = self.newsProvider?.obtainNewsForDate(date: date) // Отображаем новости }

Page 57: Сергей Крапивенский

class ViewController: UIViewController { init(newsProvider : NewsProvider) { self.newsProvider = newsProvider super.init(nibName: "ViewController", bundle: nil) }

}

Зависимость от Core Data

Page 58: Сергей Крапивенский

NewsViewController <NewsProvider>

MagicalRecord NewsProvider

Page 59: Сергей Крапивенский

Зависимости инвертированы #

Page 60: Сергей Крапивенский

Серебряной пули нет 😢

Page 61: Сергей Крапивенский

- Оноре де Бальзак

“Обстоятельства переменчивы, принципы - никогда”

Page 62: Сергей Крапивенский

Спасибо!

serkrapiv

sergey.krapivenskiy

rambler-ios