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
Мессенджер Наизнанку
Search
Max Sokolov
November 11, 2017
Programming
270
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Мессенджер Наизнанку
Max Sokolov
November 11, 2017
Other Decks in Programming
See All in Programming
【やさしく解説 設計編・中級 #6】良いアーキテクチャとは ~ 一本の登り道の、行き先 ~
panda728
PRO
0
200
Welcome to the "Parametricity" 🏙️ − Generic だけど Specific な世界 −
guvalif
PRO
1
190
TSX の <Hoge<Fuga>> という構文に驚いた話 / tsx-type-argument-syntax
kanaru0928
0
140
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
320
What's New in Android 2026
veronikapj
0
240
jsmini JavaScript Engine を作ってみた話
yosuke_furukawa
PRO
0
270
광주소프트웨어마이스터고등학교 DevFest 특강 - 바이브 코딩 시대에서 주니어 개발자로 살아남는 방법
utilforever
1
160
「寝てても仕事が進む」Claude Codeで組む第二の脳
tomoyafujita2016
0
210
作るコストが小さくなった時代 幸せに働くために改めて考えたいこと 〜エンジニアとして価値を出し続けるために注視している二分野〜
yuppeeng
0
140
GDG Korea Android: 2026 I/O Extended ~ What's new in Android development tools
pluu
0
190
JAWS-UG横浜 #102 AWSサ終供養LT会 成仏できない AWS サービスたち 〜本日、三体供養します〜
maroon1st
0
270
PHPだって関数型したい 〜できること、できないこと〜 / fp-in-php
jsoizo
1
260
Featured
See All Featured
Documentation Writing (for coders)
carmenintech
77
5.4k
Accessibility Awareness
sabderemane
1
170
Evolving SEO for Evolving Search Engines
ryanjones
0
250
Unsuck your backbone
ammeep
672
58k
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
3k
Technical Leadership for Architectural Decision Making
baasie
3
450
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
240
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2.1k
Statistics for Hackers
jakevdp
799
230k
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
3
1.1k
Testing 201, or: Great Expectations
jmmastey
46
8.2k
Transcript
МЕССЕНДЖЕР НАИЗНАНКУ Максим Соколов, iOS @ Avito Ноябрь 2017 /
Mobius max_sokolov
None
ЧТО СЕГОДНЯ УМЕЕТ ЛЮБОЙ МЕССЕНДЖЕР? 3
ТЕКСТОВЫЕ СООБЩЕНИЯ НЕОТПРАВЛЕННЫЕ СООБЩЕНИЯ ЧЕРНЫЙ СПИСОК РЕАЛТАЙМ УВЕДОМЛЕНИЯ СТАТУСЫ СООБЩЕНИЙ
ОНЛАЙН СТАТУСЫ ШАРИНГ ФОТО ХРАНИЛИЩЕ СООБЩЕНИЙ ШАБЛОНЫ ОТВЕТОВ 4
Как спроектировать все так, чтобы потом не было больно? 5
Спойлер Несколько приложений - один мессенджер 6
План Проектирование API слоя взаимодействия с сервером Проектирование сервисного
слоя Трюки и советы 7
План Проектирование API слоя взаимодействия с сервером Проектирование сервисного
слоя Трюки и советы 8
Что такое API слой? Все что умеет делать Мессенджер, но
это еще не бизнес-логика. 9
RESPONSE SERIALIZER REQUEST SERIALIZER MESSENGER CLIENT NETWORK TRANSPORT 10
RESPONSE SERIALIZER REQUEST SERIALIZER MESSENGER CLIENT NETWORK TRANSPORT 11
Сетевой транспорт TCP Socket Web Socket HTTP (Polling / Long
Polling) ? 12
Задача В приложении нужен чат, никакого своего бекенда пока нет.
13
Сетевой транспорт TCP Socket Web Socket HTTP (Polling / Long
Polling) BaaS (Backend as a Service) 14
1 x App Середина 2015 BaaS Эволюция Мессенджера 15
“APIs for developers building secure realtime Mobile, Web, and IoT
Applications.” 16
Отправить сообщение Подписаться на новые сообщения Получить историю переписки PROFIT!
Backend as a Service 17
Не все сценарии можно реализовать (статусы доставки / прочтения,
черный список)* Нет контроля над перепиской (пре-обработка / спам)* Минусы Backend as a Service 18
Забавный факт Мы использовали parse.com и он закрылся :( На
BaaS надейся… 19
1 x App Backend в разработке 1 x App Конец
2015 HTTP Середина 2015 BaaS Эволюция Мессенджера 20
Задержки (Polling / Long polling - стратегия обновлений) Лишний трафик,
накладно делать некоторые сценарии* (http заголовки + хендшейки на соединение*) Лишние запросы (новых событий может не быть) HTTP Минусы 21
1 x App 1 x App Конец 2015 HTTP Середина
2015 BaaS 4 x App Конец 2016 Web Socket Backend в разработке Эволюция Мессенджера 22
Забавный факт Пришел веб-сокет, но приложение уже написано на BaaS
- мы не хотим переписывать… 23
Web Socket Нюансы работы с веб-сокетами 24
Протокол взаимодействия клиента и сервера 25
REQUEST-1 REQUEST-2 NOTIFICATION RESPONSE-1 RESPONSE-2 CLIENT-SERVER SOCKET CONNECTION 26
JSON-RPC 27
--> {"method": "sum", "params": [41, 1], "id": 1} <-- {"result":
42, "id": 1} 28
Дублирование сообщений в UI 29
SEND MSG NOTIF MSG-ID RESP MSG-ID DEVICE-1 SOCKET CONNECTION 30
DEVICE-2 SOCKET CONNECTION ОДИН ПОЛЬЗОВАТЕЛЬ - МНОГО СЕССИЙ NOTIF MSG-ID
Добавить в тело сообщения random id, назначенный на клиенте
Обрабатывать нотификации после того, как получены все ответы к запросам Решения Дублирование сообщений 31
Ping / Heartbeat Реконнекты Background Task Поддержка соединения 32
Web Socket Ack пакетов - подтверждение получения пакетов клиентом 33
ACKNOWLEDGED MSG-1 MSG-1 iOS ANDROID MSG-1 ACKNOWLEDGED MSG-1 MESSENGER SERVER
34
Web Socket & Polling? 35
Коды ошибок при разрыве (401 / рефреш токена) Очередь
на запросы к серверу (assert на превышение) Обработка ошибок 36
Итог Выбирайте сетевой транспорт под задачу (TCP Socket / Web
Socket / HTTP / BaaS) 37
REQUEST SERIALIZER RESPONSE SERIALIZER MESSENGER CLIENT NETWORK TRANSPORT 38
socket.isConnecting? 39
enum MessengerRequestState { case ready case delayed } 40
RESPONSE SERIALIZER REQUEST SERIALIZER MESSENGER CLIENT NETWORK TRANSPORT 41
MESSENGER API CORE Unbox Unbox Unbox In-house Mapper 42
Проблема Будут ли приложения определять свой контекст моделей данных? 43
final class MessengerResponseMapperImpl { func map<T: MessengerResponseMappable>( responseData: Data, completion:
@escaping (_ result: Result<T>) -> ()) { } } 44 protocol MessengerResponseMappable: class { static func map(_ dictionary: [String: String]) -> Self? } let dictionary = jsonParser.parse(data: responseData) let value = T.map(dictionary) completion(.value(value))
extension MessengerResponseMappable where Self: Unboxable { static func map(_ dictionary:
[String: String]) -> Self? { return try? unbox(dictionary: dictionary) } } 45
Итог Не завязывайте маппинг ответов сетевого слоя на конкретную реализацию
46
MESSENGER CLIENT RESPONSE SERIALIZER REQUEST SERIALIZER NETWORK TRANSPORT 47
open class MessengerClient { /* Inject: Network transport Request serializer
Response serializer */ func getChats<T: MessengerResponseMappable>( completion: @escaping (_ result: Result<[T]>) -> Void) { } } 48
messengerClient.getChats( completion: { (result: Result<[Chat]>) in } ) 49
messengerClient.getChats( completion: { (result: Result<[OtherChat]>) in } ) 50
MESSENGER CLIENT RESPONSE SERIALIZER REQUEST SERIALIZER NETWORK TRANSPORT MESSENGER API
CORE 51
Выносите слой работы с API в отдельный модуль (мы
используем Private CocoaPods) Вывод 52
План Проектирование API слоя взаимодействия с сервером Проектирование сервисного
слоя Трюки и советы 53
Легко тестировать Легко расширять Легко переиспользовать Легко композировать сервисы друг
с другом Сервисный слой 54
Легко тестировать Легко расширять Легко переиспользовать Легко композировать сервисы друг
с другом Сервисный слой 55
НОВОЕ СООБЩЕНИЕ В ЧАТЕ СТАТУС СООБЩЕНИЯ ЮЗЕР ОНЛАЙН ЧЕРНЫЙ СПИСОК
56
МИКРОСЕРВИСНАЯ АРХИТЕКТУРА 57
CHAT LIST SERVICE USERS ONLINE STATUS SERVICE MESSAGES STATUS SERVICE
NEW MESSAGE SERVICE BLACK LIST SERVICE DELETE CHAT SERVICE REACHABILITY SERVICE 58
FAVOR COMPOSITION 59
Как связать все вместе? 60
OBSERVER PATTERN Шаблон проектирования Наблюдатель 61
protocol UsersOnlineStatusObservable: class { func add( observer: AnyObject, onUsersOnlineStatusChange: @escaping
(([User]) -> ()) ) func remove(observer: AnyObject) } 62
protocol UsersOnlineStatusService: class { func startPollingOnlineStatuses() } 63
final class UsersOnlineStatusServiceImpl: UsersOnlineStatusService, UsersOnlineStatusObservable { } 64
// MARK: - state private var chats: [Chat] { }
func subscribeOnUpdates() { usersOnlineStatusServiceObservable.add( observer: self, onUsersOnlineStatusChange: { users in // update chats } ) } 65 didSet { notifyObservers() } newMessagesServiceObservable.add( observer: self, onNewMessage: { newMessage in // update chats } )
CHAT LIST SERVICE OBSERVABLE USERS ONLINE STATUS SERVICE MESSAGES STATUS
SERVICE NEW MESSAGE SERVICE BLACK LIST SERVICE DELETE CHAT SERVICE REACHABILITY SERVICE OBSERVABLE OBSERVABLE OBSERVABLE OBSERVABLE OBSERVABLE OBSERVABLE 66
ObserverList<T>.swift http://gist.github.com 67
Микросервисы - небольшие блоки, соединяющиеся в единую систему Консистентность -
все сервисы спроектированы одинаково Выводы 68
План Проектирование API слоя взаимодействия с сервером Проектирование сервисного
слоя Трюки и советы 69
onChatListChange -> [Chat] PRESENTER VIEW INTERACTOR CHAT LIST SERVICE …
[CellData] -> setViewData 70
onChatListChange -> [Chat] PRESENTER VIEW INTERACTOR CHAT LIST SERVICE …
[CellData] -> setViewData 71
Проблема Слишком частые обновления UI 72
DEBOUNCE THROTTLE SAMPLE 73 DELAY
Sample Operator Emit the most recent items emitted by an
Observable within periodic time intervals 74
TIME TIME SAMPLE ⏱ ⏱ 75
let sampler = Sampler(delay: 0.5) sampler.sample { // update ui
here... } 76
Sampler.swift http://gist.github.com 77
Проблема Обновление UI, если пользователь покинул экран 78
final class ChatListViewController: UIViewController { func processOnChatListUpdates(_ chats: [ChatViewData]) {
} } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) invokeClosuresHelper.setViewIsReady(true) } 79 invokeClosuresHelper.invokeOrDelayIfViewIsNotReady { // do ui updates... }
Проблема UITableView / UICollectionView Обновление элементов, поиск index path изменившихся
80
Diff алгоритм ITEM 3 ITEM 4 ITEM 2 ITEM 1
ITEM 5 ITEM 4 ITEM 6 ITEM 5 ITEM 2 ITEM 7 RELOADS INSERTS DELETES 81
Выбирайте инструмент под задачу Выносите логику работы c API в
отдельный модуль Закладывайте масштабируемость Общайтесь с коллегами из других платформ Выводы 82
/MAXSOKOLOV @MAX_SOKOLOV https://github.com/maxsokolov https://gist.github.com/maxsokolov https://twitter.com/max_sokolov Вопросы?
[email protected]
Примеры кода gist.github.com/maxsokolov