
Комментарии 9
Унижение Flutter'a в статье про архитектуру в KMP умиляет)
Ни в коем случае не хотел никого унизить! Старался аргументированно описать, с какими проблемами можно столкнуться в будущем, по моему опыту.
Flutter, React Native и PWA - отличные решения для определённых задач и в определённых ситуациях. Но у них есть минусы. И важно знать о них перед тем, как написать на фреймворке огромное количество кода.
Статья про архитектуру в KMP. Статьи про Flutter не вспоминают KMP. Статьи про KMP не могут забыть Flutter. Вопрос — кто кому что доказывает?
Большое спасибо за статью! Жду продолжение с практикой)
Филин и правильная архитектура леса
Однажды Филин собрал зверей на большой поляне и объявил, что наконец нашёл единственно правильный способ обустроить лес.
— Отныне все гнёзда, норы, плотины и запасы должны строиться на 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-кода и почему одинаковые критерии по-разному применяются к твоим технологиям и к чужим.
— Это уже детали, — сказал Филин.
— Но архитектура и состоит из деталей.
— Нет, — возразил Филин. — Архитектура состоит из принципов.
— А как применить принцип без деталей?
— Правильно.
— А как понять, что правильно?
— Нужно следовать критериям.
— Каким?
Филин тяжело вздохнул.
— Я же только что всё объяснил.
Звери переглянулись. Бобёр вернулся к плотине, Лиса — к норам, Выдра — к общим компонентам. Белка подписала свою записную книжку: «Чёткие критерии Филина» — и оставила все страницы пустыми, чтобы не исказить смысл.
Филин же ещё долго сидел на поляне и жаловался, что лесным зверям не хватает архитектурной зрелости: им всё время нужны определения, сравнения, цифры и причины, когда он уже дал им самое главное — уверенный ответ.
Лучшая архитектура KMP-приложений и когда её не использовать. Часть 1