Обновить

Лучшая архитектура KMP-приложений и когда её не использовать. Часть 1

Уровень сложностиСредний
Время на прочтение12 мин
Охват и читатели4.5K
Всего голосов 3: ↑3 и ↓0+5
Комментарии9

Комментарии 9

Унижение Flutter'a в статье про архитектуру в KMP умиляет)

Ни в коем случае не хотел никого унизить! Старался аргументированно описать, с какими проблемами можно столкнуться в будущем, по моему опыту.

Flutter, React Native и PWA - отличные решения для определённых задач и в определённых ситуациях. Но у них есть минусы. И важно знать о них перед тем, как написать на фреймворке огромное количество кода.

Статья про архитектуру в KMP. Статьи про Flutter не вспоминают KMP. Статьи про KMP не могут забыть Flutter. Вопрос — кто кому что доказывает?

Вы правы, в статьях про Flutter обычно не говорят про KMP. Но, с другой стороны, никто же не запрещает этого делать =)

Опять же, не хейта ради, а аргументации для.

Большое спасибо за статью! Жду продолжение с практикой)

Благодарю! Планирую выпустить вторую часть в ближайший вторник.

Филин и правильная архитектура леса

Однажды Филин собрал зверей на большой поляне и объявил, что наконец нашёл единственно правильный способ обустроить лес.

— Отныне все гнёзда, норы, плотины и запасы должны строиться на Kotlin, — сказал он. — Для серьёзного леса другой технологии не существует.

Первым возразил Бобёр.

— Моя плотина работает на Flutter уже шестую весну. На одном Dart я управляю и северным шлюзом, и южным. Вода не протекает, брёвна переиспользуются, а новые запруды я собираю быстрее, чем раньше.

Филин осмотрел плотину издалека и покачал головой.

— Это годится, пока у тебя маленький стартап. Когда плотина станет большой, ты всё равно перепишешь её на нормальные нативные брёвна.

— Но она уже большая, — заметил Бобёр.

— Значит, переписывать придётся особенно долго, — заключил Филин.

Тогда заговорила Лиса.

— Я построила сеть нор на React Native. Общая схема ходов хранится в TypeScript, а там, где нужно пройти под корнем или обогнуть камень, я использую Native Module. Лисята уже несколько поколений по этим норам бегают.

— Вот именно, — ответил Филин. — Раз тебе потребовался Native Module, значит, вся система архитектурно несостоятельна.

— А ты разве не используешь expect/actual, когда одной сове нужно гнездо в сосне, а другой — в дупле?

— Это другое, — строго сказал Филин. — У меня не костыль, а платформенная абстракция.

Из ручья показалась Выдра. Она принесла с собой Decompose — специальную систему, по которой вся её семья делила между берегами маршруты, состояния и правила поведения.

— Мы держим общую navigation logic, — объяснила Выдра. — Если детёныш нырнул у старой ивы, все платформы знают, где он должен вынырнуть. А внешний вид берега при необходимости делаем разным.

Филин нахмурился.

— Общая presentation logic опасна. Лучше дважды описать, куда плыть, дважды проверить течение и дважды исправить ошибку, если кто-то заплывёт не туда.

— Но тогда берега начнут вести себя по-разному, — сказала Выдра.

— Зато нативно, — ответил Филин.

Белка спросила, как ей хранить орехи.

— Используй Clean Architecture, — посоветовал Филин. — Сначала положи орех в Repository, затем передай его в UseCase, после этого преобразуй в Domain Model и только потом отправляй в Presentation Layer кладовой.

— У меня всего три ореха, — сказала Белка.

— Архитектура должна быть готова к масштабированию, — объяснил Филин.

— А если орехов станет четыре?

— Добавишь ещё один модуль.

Крот поинтересовался, нужно ли проверять новый туннель перед зимой.

— Если ты стартап, тесты только замедлят выход на рынок, — сказал Филин. — Главное — быстрее проверить гипотезу, можно ли вообще жить под землёй.

— Но мы живём под землёй много поколений.

— Значит, гипотеза перспективная.

Потом Филин показал зверям своё новое настольное гнездо.

— Я перенёс его на Desktop почти бесплатно, — похвастался он.

Звери увидели, что у гнезда не было двери, мышь не могла открыть его двойным щелчком, клавиатура застревала между ветками, а на Windows его вообще не удавалось поставить.

— Это мелкие платформенные доработки, — пояснил Филин. — Архитектурно всё уже готово.

Старый Ёж всё это время молчал. Наконец он спросил:

— А как ты выбираешь технологию?

— Очень просто, — ответил Филин. — Сначала определяю, насколько проект серьёзный. Если серьёзный — выбираю Kotlin. Если выбран не Kotlin, значит, проект был несерьёзный.

— А сравниваешь ли ты стоимость двух реализаций? Учитываешь ли опыт команды? Проверяешь ли свои выводы на чужих успешных проектах?

— Зачем? — удивился Филин. — Я уже выбрал правильную архитектуру.

Звери разошлись по своим делам. Бобёр продолжил расширять Flutter-плотину, Лиса обновила React Native-норы, Выдра вынесла ещё один маршрут в Decompose, а Белка просто положила четвёртый орех рядом с первыми тремя.

Филин же остался на поляне и до вечера объяснял пустым пням, почему все остальные через два года обязательно придут переписывать к нему свои дома.

Мораль: хороший архитектор не объявляет знакомый ему инструмент единственно взрослым. Он сравнивает варианты по одинаковым критериям и выбирает решение под конкретный лес, зверей и задачу. А тот, у кого на любой вопрос один ответ, обучает не архитектуре, а собственной привычке.

Отличный текст! И мораль очень правильная! Поэтому в тексте столько оговорок про условия применения "хорошей" архитектуры. Да и сам текст Филин назвал "... и когда её не использовать".

На следующее утро Филин снова созвал зверей на поляне.

— Я слышал, вы говорите, будто мои рекомендации слишком категоричны, — начал он. — Это несправедливо. Я дал совершенно чёткие критерии.

— Какие именно? — спросила Выдра.

— Всё просто. Если продукт большой, долгоживущий и серьёзный, ему нужны нативные берега, отдельные Presentation-норы и общий только склад припасов. Если продукт маленький, временный и несерьёзный, можно использовать общий Compose-хворост.

Бобёр поднял лапу:

— А моя плотина большая, долгоживущая и вся построена на Flutter. Шестой год стоит. К какой категории она относится?

Филин задумался.

— Если она на Flutter, значит, пока ещё не стала по-настоящему большой.

— Но по ней уже проходит половина лесной реки.

— Размер определяется не водой, — пояснил Филин. — Размер определяется зрелостью архитектуры.

Лиса спросила:

— У меня большая сеть нор на React Native. В ней общая логика маршрутов, а сложные участки сделаны нативно. Это большой продукт или стартап?

— Пока вы его не переписали, это растущий стартап.

— А когда он перестанет быть стартапом?

— После переписывания.

Выдра развернула схему своих берегов.

— У нас большой продукт, общий Decompose, общий Presentation и CMP. Платформенные различия мы выносим в отдельные компоненты. По твоим критериям это допустимо?

— Нет, — ответил Филин. — Для большого продукта Presentation должен быть раздельным.

— Почему?

— Потому что продукт большой.

— Но разве выбор не зависит от похожести сценариев, опыта команды и стоимости поддержки?

— Конечно, зависит.

— У нас одинаковые сценарии, Kotlin-команда и дорогая двойная поддержка.

— Тогда у вас особый случай.

— Значит, твой критерий не «большой продукт», а сочетание нескольких факторов?

— Именно это я и сказал.

— Где?

— Между строками.

Белка открыла записную книжку.

— Давай я проверю, правильно ли поняла. Если приложение большое, но платформы похожи, команда Kotlin-first, нативных интеграций немного, а Presentation сложный, то можно шарить Presentation и CMP?

— Теоретически можно, — неохотно сказал Филин.

— А если приложение маленькое, но платформы сильно различаются и почти всё зависит от нативных SDK?

— Тогда лучше нативно.

— Получается, размер приложения сам по себе ничего не решает?

Филин расправил крылья.

— Вы опять всё упрощаете. Размер — главный критерий, кроме тех случаев, когда он не главный.

Крот спросил:

— А как понять, когда он главный?

— По архитектурному опыту.

— Чьему?

— Моему.

На поляне стало тихо.

— Я не понимаю, почему вы все запутались, — продолжил Филин. — Я дал таблицу. Там было написано: большой продукт — одна архитектура, стартап — другая, утилита — третья. Что здесь может быть непонятного?

Ёж посмотрел в таблицу.

— Непонятно только, что такое «большой», что такое «сложный», что значит «максимально нативный», сколько стоит две Presentation-логики, сколько допустимо interop-кода и почему одинаковые критерии по-разному применяются к твоим технологиям и к чужим.

— Это уже детали, — сказал Филин.

— Но архитектура и состоит из деталей.

— Нет, — возразил Филин. — Архитектура состоит из принципов.

— А как применить принцип без деталей?

— Правильно.

— А как понять, что правильно?

— Нужно следовать критериям.

— Каким?

Филин тяжело вздохнул.

— Я же только что всё объяснил.

Звери переглянулись. Бобёр вернулся к плотине, Лиса — к норам, Выдра — к общим компонентам. Белка подписала свою записную книжку: «Чёткие критерии Филина» — и оставила все страницы пустыми, чтобы не исказить смысл.

Филин же ещё долго сидел на поляне и жаловался, что лесным зверям не хватает архитектурной зрелости: им всё время нужны определения, сравнения, цифры и причины, когда он уже дал им самое главное — уверенный ответ.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации