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

Preview:

Citation preview

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

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

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

“Do Not Learn Frameworks”

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

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

Язык

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

Язык

Фреймворки

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

Язык

Фреймворки

RayWenderlich - driven development

Senior ReactiveCocoa Developer

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

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

Язык

Фреймворки

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

Язык

Фреймворки

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

Язык

Фреймворки

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

• Алгоритмы

• Паттерны

• DRY, KISS, YAGNI

• SOLID

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

Single responsibility principle

Open-closed principle

Liskov substitution principle

Interface segregation principle

Dependency inversion principle

Single Responsibility Principle

“A class should have only one reason to change”

MassiveViewController

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

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

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

UITableViewController

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

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

UITableViewController

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

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

Push Notifications

Quick Actions

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

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

Фоновая

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

AppDelegate

AppDelegate

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

ПоискPush Notifications

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

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

Handoff

Extensions

AppDelegate

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

ПоискPush Notifications

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

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

Handoff

Extensions

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

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

Single responsibility principle

Open-closed principle

Liskov substitution principle

Interface segregation principle

Dependency inversion principle

Open-Closed Principle

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

modification”

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

Новость

Новость

Новость

Новость

Новость

Новость

Новость

Новость

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

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

Новость

Новость

Новость

Новость

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

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

Реклама

Реклама

} 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)

} 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)

} 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)

} 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)

} 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)

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 }

NewsCell PhotoCell AdCell

<ConfigurableCell>

func configure(withObject: CellObject)

News Photo Advert

<CellObject>

func cellClass() -> AnyClass

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

Single responsibility principle

Open-closed principle

Liskov substitution principle

Interface segregation principle

Dependency inversion principle

Liskov Substitution Principle

“Subtypes must be substitutable for their base types”

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

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

UIView

UIVisualEffectView

Всё ок !

<UIVisualEffectView> is being asked to animate its opacity. This will cause the effect to appear broken until

opacity returns to 1

¯\_(ツ)_/¯

Single responsibility principle

Open-closed principle

Liskov substitution principle

Interface segregation principle

Dependency inversion principle

Interface Segregation Principle

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

do not use”

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

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

ISP - это не SRP

- 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

Single responsibility principle

Open-closed principle

Liskov substitution principle

Interface segregation principle

Dependency inversion principle

Dependency Inversion Principle

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

should depend on abstractions”

Dependency Inversion Principle

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

on abstractions”

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

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

NewsViewController MagicalRecord

Realm😓

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

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

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

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

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

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

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

}

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

NewsViewController <NewsProvider>

MagicalRecord NewsProvider

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

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

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

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

Спасибо!

serkrapiv

sergey.krapivenskiy

rambler-ios