Как стать автором
Обновить

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

Как обратиться к ресурсам приложения из библиотеки? Например, надо выбросить исключение и показать сообщение об ошибке на языке пользователя. Или перечисления с текстовым представлением.

Любая библиотека всегда находится на самом низком уровне зависимостей. То есть она априори не может быть зависима от нас. В таком случае у нас остается только вариант инверсии зависимостей. Когда библиотека выдает контракт в виде интерфейса, который мы должны реализовать и передать ей при инициализации. Это может также выглядеть как плагины, подключаемые к библиотеке или другие способы инверсии зависимостей.

В рамках текущей статьи это не имеет значения, поскольку модули feature level имеют право зависеть от публичных модулей из уровней ниже. А управление зависимостями и инициализации происходят на Application уровне.

Звучит красиво. Давайте к практике. Есть enum. у него есть текстовое поле. Как реализовать эту самую инверсию зависимостей данном случае?

А где этот enum лежит? Где и для чего используется? Я не очень понимаю условия вопроса. Можете, пожалуйста, предоставить более подробное описание проблемы?

У Андроид есть context, который нужен для доступа к ресурсам приложения. (Зачем они так сделали?) Из-за этого периодически возникают сложности. Как осуществляется доступ к context?

Доступ к контексту есть только в 2 местах.
AppContext - при создании графа зависимостей, чтобы создавать различные библиотечные зависимости.
ActivityContext - на View, чтобы достать что-то из ресурсов. Можете почитать о том, как делаются обертки Text, которые получают значения из ресурсов при установке во View, или про то, как делают ResourceWrapper, для ViewModel.

А так, если у вас вопрос, для чего они так поступили с контекстом, то советую лучше ознакомиться с его документацией. Возможно у вас появится более хорошее архитектурное решение и нам всем станет жить легче)

То есть вы предлагаете хранить ID ресурса и далее выписывать везде обертки?

Как быть в случае, когда библиотека не знает, будет ли она работть на мобильной платформе, или на обычной?

Я так и не понял как связаны ресурсы и библиотека)

Работа с ресурсами происходит на View, но при этом ViewModel может знать про существование ресурсов, их id и возможно способ как их достать,

Если говорить про библиотеку, она должна проектироваться совершенно без знаний о том, где будет применяться.
Она может быть заточена под использование на конкретной платформе, например, предоставлять ui для android. Тогда это android либа, которая может иметь собственные ресурсы и способы с ними работать. При этом из библиотеки ты никак не может иметь доступ к внешним ресурсам.

Пока что я ничего не предлагаю, потому что не понимаю вопроса. Раскройте, пожалуйста, вопрос более подробно, чтобы я мог предложить вам какое-либо решение)

Давайте такие варианты рассмотрим, например.

Есть библиотека, которая ничего не знает о том, на какой платформе запускается. Содержит enum-ы с текстовым предатсвлением, тажде ей надо выкидывать исключения. Обычно исключение содержит текст сообщения. Как бы вы спроектировали?

Если вы посмотрите тот же stackoverflow, достаточно много вопросов по доступу к контексту и ресурсам статически как раз из-за таких проблем.

и в чем проблема, я не понял? как это вяжется с контекстом, с какими-то ресурсами о которых выше речь шла?

Доступ к текстовым ресурсам осуществляется через context.

да эт ясно дело, и? у тебя метод библиотеки выкидывает эксепшн с текстовым значением (ты написал), а не ссылкой на ресурс, который ты должен вытягивать??‍♂️ Ты же сам написал, что библиотека ничего о платформе Андроид не знает, стало быть и никаких ресурсов в либе быть не должно. Метод возвращает ошибку с текстом, ты или прокидываешь текст до ui или пишешь какой-то эксепшн хендлер, который приводит инфу об ошибке к нужному виду.

Пример, пожалуйста.

Вы предлагаете писать что-то типа такого?

throw new MyException("Деление на 0");

и далее при перехвате:

catch(MyException e) {
    if( "Деление на 0".equal( e.getMessage() ) ) {
        String text = context.getString( R.string.ExDivZero );
    }
}

class LibException : Exception()

class LibExceptionHandler(private val context: Context) {
    fun handleException(exception: LibException) {
        when (exception.localizedMessage) {
            "Exception 1" -> context.getString(R.string.text_error_1)
            "Exception 2" -> context.getString(R.string.text_error_2)
            else -> context.getString(R.string.text_error_404)
        }
    }
}

class MySomeClass(private val libExceptionHandler: LibExceptionHandler) {
    fun doSome() {
        try {
            // TODO: code
        } catch (e: LibException) {
           val exMessage = libExceptionHandler.handleException(e) 
           ...
        }
    }
}

Ну а почему нет? Только не в каждом кэтче чекать, а написать класс обработчик ошибок. Но если в либе изменятся данные ошибок, то могут быть проблемы, даа. Разве плохой вариант, а есть лучше подход?

в коде косяк, нужно чтоб метод handleException возвращал String.

Вам нравится такое решение?

меня устраивает, есть вариант лучше?

Обработка по сообщению это очень странное решение. И опасное, потому что текста ошибок могут меняться как угодно. Это не часть интерфейса взаимодействия с библиотекой.

Если вы пишите либу, которая кидает какие-то специфические исключения, которые должны быть обработаны во внешнем коде, то это ответственность внешнего кода.
Вы должны только создать специальные типы исключений, чтобы по типу можно было определить что это такое.

Приемлемый вариант, это одно кастомное исключение, которое внутри содержит код ошибки. И по этому коду внешние разработчики должны обрабатывать эти исключения. А коды должны быть зафиксированы в документации, чтобы внешние разработчики их хорошо понимали. Как пример, коды REST ответов. 404 это код ошибки, который знают все. Но ни кто не завязывается на текст Not found.

Уточню, что если у вас не так много возможных ошибок, как в rest, то лучше не поленитесь и сделайте разные типы через сайлед класс или хотя бы ключи через енам, чтобы удобно можно было итерироваться при обработке.

Касаемо того, что вы хотите из либы возвращать текст ошибки, который должен быть показан пользователю, это плохая идея. При проектировании, вы не знаете, кто и как будет использовать вашу либу и поэтому ответственность за то, как ее будут представлять пользователю, должна лежать на внешнем разработчике. Он определяет что и как показывать пользователю. А сообщение об ошибке должно быть на английском языке, чтобы этот самый внешний разработчик лучше понял что это за ошибка и почему она возникла. И чтобы он ее увидел в стектрейсе или отправил в логи или метрики, но ни как не показывал пользователю.

Вообще, библиотека должна иметь свои исключения, типа Exception1, Exception2, а уже на View уровне уже catch(Exception1) {
toast(getString(R.id.exception1Message))
} catch ...
...
Всё же
*(JNIEnv)->ThrowNew(...) никто не отменял.

Ну или же уже не в нативе делать, что-то вроде

when (callMyNative()) {
MyLib.Exception1 -> ...
}

Поддерживаю!

К сожалению без знания основ, я не смог понять всю суть, хотя статья показалась мне очень интересной (.

За несколько лет коммерческой разработки мне ни разу не приходилось сталкиваться с необходимостью в интерфейсах interface UseCase и interface FeatureCase
Аргумент про тестирование? Любой сахарный фреймворк для тестов и так отлично замокает все наши классы.

В общем, для меня неочевидно, зачем эта абстракция.

Нужно понимать объем приложения. Проблемы скорости сборки ни кто не отменял для больших приложений. И одно из решений это разбиение на маленькие модули по принципу api/impl, чтобы завязка была на интерфейсы, которые имеют гораздо меньший коэффициент изменчивости, по сравнению с реализацией.

А так же интересно посмотреть, как вы разобьете функциональность на модули, не имея интерфейсов, сохранив при этом гибкость переиспользования различных компонентов.

Есть два экрана которым нужен один и тот же список данных. Пусть у нас будет какой-нибудь FetchItemsUseCase, юзкейс возвращает список данных доменного уровня, т.е модели не готовы к использованию на UI, чтоб их приготовить, мы должны во viewModel смапить домейн лист к ui листу. Правильно? Дак вот, мы должны в каждом модуле создавать свою модель и маппер для работы с домен уровнем? Горизонтальные зависимости запрещены и если я правильно понял, то и создание модуля содержащего общую ui модель и маппер тоже нельзя, так? Но тогда мы получаем копипасту. Как быть?

В данном случае, мы можем вынести в отдельный модуль, на уровень common, view для нашего списка и модель этого списка. Они связаны 1к1. Маппинг мы не сможем сюда вынести, потому что это уровень common, а связи снизу вверх запрещены.
В 2 разных screen модулях мы можем зависеть от одних и тех же feature-api и common-my-list-ui.

В такой ситуации нам придется продублировать маппинг в каждом из screen модулей.
Важно понимать, что дублирование это не плохо. В данном случае у нас есть 2 независимых друг от друга экрана и каждый из них может измениться самостоятельно, изменив как отображение, так и логику получения данных.

К тому же, такая схема позволяет использовать ui для списка не только с этими данными, но так же и с другими данными из других предметных областей.

А дублирование, это не плохо. Бывают случаи, когда лучше 10 раз продублировать, чем после пытаться внести изменения для каких-то случаев в общий код, который мы решили не дублировать.

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

Только начал, поэтому не судите строго) И пока особо нету времени активно продолжить, но обещаю, что не заброшу) https://github.com/NekrutovEd/EasyFinance

Супер!?

И все же я никак не могу найти время на реализацию демо проекта. Все время про это вспоминаю. Много изменений в жизни, которые совершенно не оставляют на это времени. Возможно когда-то, но не сейчас...

"И только в 1989 создали привычный нам чемодан на 2 колесах с выдвижной ручкой.

Более 120 лет, на то, чтобы придумать колесо."

Думается, привычный нам чемодан на 2 колесах 120 лет пришлось бы носить, ввиду отсутствия ровных полов в достаточном количестве.

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

Эта история больше о том, что очевидные для нас вещи, не всегда являлись очевидными. Казалось бы, что может быть очевиднее коробки для бумаг или раскладывания документов по папкам и стопкам? Однако люди долгое время перевязывали стопки бумаг веревками и складывали их в кучу "как-то". На самом деле, существует достаточно много таких случаев, когда казалось бы очевидные для нас вещи, никому не приходили в голову.

По поводу чемодана. Чтобы использовать колёса -нужна крепкая рама, а это сильно прибавит вес, да и цену увеличит значительно. Современный пластик и толковые сплавы принесли чемоданостроению колёса.

Хотелось бы верить, что у человечества были рациональные причины, но верится с трудом) Можете загуглить первые чемоданы от луи виттон, они так и просят приделать к ним не менее маленькие колеса)

"Первой ступенью эволюции чемодана стал дорожный сундук из ценных пород дерева — сосны, кедра, дуба, обитый для прочности металлическими полосами, украшенный декоративными гвоздями и застежками."

Осталось подождать ещё 120 лет, чтобы во всех лестницах добавили более пологую полосу для качения, а так же во все бордюры добавили частый сьезд, а также чтобы везде рядом с брусчатской/плиткой добавили ровную дорожку для использования колёс.

Пару лет назад помогал колясочнице доехать в Мск от кинотеатра Октябрьский до Гагаринского переулка... Это был не простой квест даже для 2х сопровождающих мужчин.

Ну и периодически приходится с чемоданом ехать от вокзалов на метро с пересадками и многие станции не предназначены для использования чемоданов с колесами (хоть формально там сделаны полозья, которыми невозможно пользоваться), приходится часто нести чемодан на руках.

Очень хочется посмотреть на пример приложения, которое построено по данным принципам. А вообще статья топовая! Жду продолжения. Очень познавательно! (Спойлеры с объяснением "для детей" вообще топ! Это очень грамотно.)

Большое спасибо за обратную связь, я старался)

Я правильно понял, что если у нас, например, 10 feature-api, 5 data-api, то это 15 модулей, в каждом из которых лежит по одному интерфейсу? Или это 2 модуля, в одном из которых 10 интерфейсов и в другом 5?

Отличный вопрос!) Чисто физически можно сделать и так и так. Однако, сложив все в один модуль, мы теряем преимущества модуляризации. Разбив модули по 1 интерфейсу, мы создаем излишний оверхед.

Лучшим критерием объединения модулей является общий контекст. Например:
data-api которые возвращают Chat и Message, лучше объединять, потому что это связанные сущности. Однако feature-api по работе с чатами, можно отделить от feature-api по работе с сообщениями, так как использоваться они будут в разных контекстах. При этом мы не отменяем того, что в контексте чата мы можем возвращать список чатов вместе с последним сообщением.

Есть правила клин, есть правила солид, еще теперь эти правила которые те же яйца только сбоку. И в которых, кстати, упущена судьба ентити. Про направление есть, а про ентити нет - а ведь это важная деталь об которую и ломаются, собственно, эти направления.

Ну то есть ты говоришь человеку что интерфейс репозитория это доменная сущность, и он отдает доменный же ентити, которые не могут иметь зависимостей от аннотаций его ORM/Serializer, а он прикидывает сколько ему делать конвертеров для DTO/DBO и не делает буквально только для этого. А потом вместо него приходит еще один и начинает использовать имеющуюся зависимость и в хвост и в гриву, хотя для одного автора такой подход был допустимым. И будет допустимым в проекте с небольшим или однообразным доменом и жесткой конвенцией. Но у тебя текучка, слабый архитектурный контроль и все накрывается одним местом.

А так конечно неплохой пример имплементации клина для внутренних конвенций конкретного проекта. Несколько царапают глаз ультимативные заявления, потому что можно эту схему переколбасить десятком способов не нарушая ни самого клина, ни заявленных дополнительных правил. Есть, например, чудесные комбайны которые делают BLoC, причем не как ui-стейт-менеджмент, а вполне себе подходящим для доменного уровня образом. Да и еще много чего есть.

Ну и на вкусненькое мое любимое - разбиение на модули не предназначено для ускорения сборки проекта. То есть это не значит что оно не может ускорить. Но оно не для этого. В реальной жизни почти всегда накладных расходов на градл наваливается столько, что выигрыш от распараллеливания сборки модулей съедает весь профит. Максимум

Вообще эта легенда родилась у незатейливых слушателей на конференциях, где докладчики из бигтеха, вынужденные пользоваться разбиением в инфраструктурных целях, сталкиваются с тем что градл у них немножечко умирает от тысяч модулей. И они начинают уже эту проблему решать. А после гордо несут ее на конференцию, неосмотрительно назвав доклад "как я ускорил сборку проекта разбив его на модули", хотя это, мягко говоря, не совсем так. Сначала мы родили проблему разбиением, потом переразбили, частично решив проблему. За кадром как обычно самое главное - жирнющие монорепы на всю линейку продуктов, необходимость структурирования кода для нескольких автономных команд в десятки человек и прочие инфраструктурные фокусы. Не у всех, но как правило. Обычно говорят о том как правильно разбивать, а не о том зачем.

Много вопросов в одном комменте) Давайте по порядку)

Entity

Это не просто очередное изложение по книге чистая архитектура. В статье есть заимствование принципа разделения на слои, но и оно было переосмыслено под фрактальное представление. Схема проектировалась для любой абстрактной системы, то есть без привязки к структурам какой-то конкретной системы. По этой причине, тут нету определения entity. Потому что entity это всегда про конкретную систему.

Я предлагаю оперировать только понятием структура данных, которая при этом не является ядром системы. Структуры данных изменчивы и не постоянны. А вот правила работы со структурами, являются более стабильными частями, которые меняются реже. Наглядным примером является мак. Была одна система с сущностями в виде бигмака и прочего. Теперь это другая система с теми же сущностями и правилами, но структуры данных оказались изменены. Терминалы, стойка выдачи заказа, кухня и прочее никак не изменились. Только бигмака больше нету. Есть что-то похожее, с измененным названием и составом. Но правила работы с "этим" не изменились. Поэтому entity не является ядром системы и системы не стоит проектировать вокруг них.

При этом структуры данных в статье описаны и представлены на схемах в виде разноцветных фигур на сущностях, которым они принадлежат. Это уже не первый комментарий, что эта тема недостаточно раскрыта, поэтому я постараюсь ее описать в следующих частях.

Слабый архитектурный контроль

Без контроля будет хаос. Первый шаг к контролю, зафиксировать правила по которым должен развиваться и создаваться проект. Если зафиксировать правила самому не получается по различным причинам, то можно взять эту или любую другу статью по архитектуре и сказать, что мы пишем по ней. Если новые разработчики этого не соблюдают, то никакая статья или доклад не сможет решить эту проблему. Тут вопрос к менеджменту и руководству.

Ультимативные заявления

Я рад, что они царапают глаза) Именно этого эффекта я и пытался добиться)
Они являются ультимативными, чтобы уменьшить возможность для споров без аргументов. А если у вас есть весомые аргументы того, что что-то можно сделать по другому, в каких-то случаях, то вы уже являетесь опытным проектировщиком, который в состоянии сделать хорошую архитектуру для этих конкретных случаев. И тут я уже буду рад выслушать эти аргументы, вместе спроецировать их на абстрактную систему, которая опишет большинство случаев, и внести правки в статью и схему. Так что если есть такие аргументы и предложения по улучшению, буду очень раз их услышать или даже созвониться и обсудить)

Разбиение на модули

К сожалению, я полностью с вами согласен в этом вопросе. Обычно говорят как правильно разбить, а не о том зачем. Если вдуматься в вопрос "зачем", то мы получим примерно такой ответ: "выделение частей программы в отдельные самостоятельные части, для облегчения восприятия кода и улучшения контроля над сложностью". Отличная формулировка благих целей. Вот только: "Для моего маленького проекта, это совсем не нужно, поэтому я буду делать все в монолите. Я же не бигтех)"

После такого ответа, человек пару лет фигачит тонны кода в монолит, пока проект не начнет развиваться, а команда не начнет расти. После этого момента, возникает как раз таки вопрос разделения на модули, чтобы именно облегчить восприятие и улучшить контроль. Для этого мы начинаем выносить в модули что? Правильно, большие куски, которые связаны одним контекстом. После чего возникает хаос в модулях и зависимостях, из-за чего сильно просаживается скорость сборки. И только тут мы начинаем переразбивать наши модули, чтобы решить и эту проблему то же.

Чтобы пропустить этот этап "разбиения по контексту хоть как-нибудь", я и описываю сразу следующую цель модуляризации, а именно сокращение нагрузки на сборщик.

При этом цель разбиения по контексту, решается на более раннем шаге, при определении зон ответственности и выделении сущностей. Вам остается только объединить сущности одного типа в модули с общим, конкретно для вашего проекта, контекстом.

Если у вас есть предложения по улучшению каких-либо формулировок или блоков в статье, я буду крайне признателен, и обязательно их рассмотрю и внесу исправления в статью)

С ентити не особо понял вашу мысль. Ядро у нас это доменные интерфейсы, сигнатуры его методов в хорошей архитектуре всегда зависят от сущностей и более ни от чего. Сущности же не зависят ни от чего вообще. Пользуясь вашей аналогией, если в вашей системе появится сущность бигмака - она появится и в ядре (надеюсь я верно уловил аналогию). В фудтехе, раз уж мы про еду, это обычно блюдо, наследуемое от товара, который в свою очередь наследует какую-нить "позицию", если там появдяется например "услуга", то у нее появятся свои специфические бизнес-кейсы и она так же унаследует позицию, чтобы посредством общих кейсов для позиции например оказаться в чеке.

Насчет ультимативности - мне например не нравится такое деление. И такая терминология. И тут я отдаю себе отчет что это вкусовщина. Мне как раз и не нравится что нет допуска вкусовщине в рамках фундаментальный принципов. Помните VIPER? Был еще шуточный репозиторий на гитхабе с его перефразом. История его зашла в тупик довольно быстро. Сам по себе подход ок. Но это конкретная имплементация некоторых принципов для конкретного случая. Мир куда разнообразнее и строить архитектуру и инфраструктуру проекта надо с оглядкой на совсем не технические факторы. Тут даже дело не в бигтехе, точнее не совсем в нем. Супераппом станет дай бог 1% приложений, 99% не дорастут даже до объема в 300K строк. Из них еще меньше дорастет до своего объема не за счет богатого домена, а не бесконечного дублирования презентационных фич с вариациями. Опять же из-за плохой структурированности GUI. Вследствие отсутствия ресурсов на подготовку собственного юай-кита и плохой продуктовой проработки. Видите: одно за другое, одно за другое.

Тут и упомянутый плохой архитектурный контроль вылезет. И приходим мы на проект чаще всего не на начальной стадии, а когда эти детские болезни развиваются в патологию. То есть особенности принятых решений вносят существенное время в реализацию не только новых фич, но и в стабилизацию старых. И тут нельзя просто взять схему и все пересобрать. Берется что есть, это "что есть" рефакторится по чистым фундаментальным вещам. И уже после этого этапа можно работать с архитектурой. Но. Это. Все. Очень. Дорого. И тут я за 20 лет практики рецепта не придумал. Если вы думаете что ваша ультимативность поможет проекту лет через пять, уже без вас, не упасть в эту яму - вы заблуждаетесь. Максимум - его не успеют слишком уж изуродовать до тех пор пока он не перейдет под контроль к хорошему лиду.

Насчет модулей примерно те же возражения - я видел как вы выражаетесь "монолиты" которые более приспособлены для разделения на модули нежели изначально многомодульные приложения которым имеет смысл такими быть. Хотя "монолиты" вовсе из другой оперы. Сервисы в бекенде это по своей сути отдельные приложения, выполняющие свои узконаправленные функции, а не какие-то там библиотеки, которые компонуются в одно. В общем случае монолитный сервис бека может быть так же попилен на модули. И собираться в монолит, который фиг попилишь на отдельные. Так что, опять же, терминологическая путаница нас тут поджидает. Но в целом хорошо что мы сходимся в целях модульности.

А претензий у меня на самом деле нет. У вас есть свое мнение и какое-то видение. У меня есть свое. Я тут ради подискутировать на досуге.

Не является ли лишним дополнительная абстракция для use cases в виде интерфейсов кейсов и их impl? Опыта коммерции я не имею, студент, возможно я просто не представляю объем приложений и проектов. В оф документации от гуглов об этом подходе не говорится, а примеры приводятся сразу в виде классов, у которых переопределен operator invoke.

Могу сформулировать такую мысль, для всех тех, кто считает, что интерфейсы являются излишними, хотя надеялся что получится без этого)

В определенных случаях, для некоторых бизнесов, при конкретных планах развития, интерфейсы для сущностей UseCase и FeatureCase, действительно могут являться излишними. Ваш большой опыт разработки и насмотренность на различные проекты, может позволить вам это понять. Вот только у новичков или мидл разработчков такого опыта не хватает или его вообще нету. Поэтому для них и пишутся правила так, чтобы эти абстракции были всегда.

Если вы в состоянии взвешено и рационально принять решение о том, что в вашем случае какие-то абстракции являются излишними, то это признак того, что у вас достаточно опыта, чтобы понимать различные принципы архитектуры и не задавать подобные вопросы, чтобы не вводить в заблуждение новичков. Если вы сомневаетесь в необходимости интерфейсов, то для вас интерфейсы обязательны. Хуже они не сделают точно, поэтому гораздо лучше сделать лишнюю абстракцию, чем не сделать ее там, где она окажется нужна.

Касаемо офф доки гугла. Там написано, что domain слой является опциональным. Я в корне не согласен с этим утверждением, поэтому эту статью можно считать противоречащей официальной документации от гугл. Я этого не отрицал и даже упомянул про это утверждение в описании одной из картинок, про разделение на слои.

Очень напоминает принципы FSD (Feature Sliced Design). Общие предки.)

Мне не были знакомы принципы FSD, так что предки разные) Постараюсь подробнее почитать и найти сходства, а пока отвечу так.

Основное заимствование для статьи это шаблон mvvm и принцип разделения на слои из чистой архитектуры. При этом он дополнительно переосмыслен во фрактальное представление зон ответственности. Все остальное описано и спроектировано без дополнительных источников или ссылок на что-либо)

200 тысяч единиц статей про архитектуру в Android уже готовы и ещё миллион на подходе... Все статьи про те же подходы к модульности закончились ещё году в 2021, и ничего нового не появилось. Максимум в какой-то компании могут какие-то особые классы иначе распределять и из этого выстраивать свой подход.
Всё описанное действительно существует, и имеет свои плюсы-минусы и разные варианты применения в индивидуальных условиях проектов и компаний, но описано было давным-давно... Зачем это всё...

Как описание подхода к проектированию больших приложений - ок.

Как руководство к проектированию любой системы - нет, т.к. оторвано от реальной жизни, где бывают и маленькие проекты, и текучка кадров, и решения по слиянию/разделению приложений и прочее.

Например сейчас я занимаюсь проектом, который сначала сделали сложным (примерно как описано в статье) на миксе архитектур Clean+MVVM, потом другой разработчик пришёл и решил "упростить" переписав часть приложение в что-то вроде MVI. Я уже 3й разработчик и пытаюсь во всём этом разобраться. Мозг взрывается от смеси 2х архитектур. Если бы приложение было на чистом MVP или MVVM - то я мог бы стоящие передо мной задачи сделать за полчаса каждую. Но в итоге уже несколько дней сижу, пытаясь понять, как прогнать данные через несколько "слоёв" или "зон ответственности", чтобы оно корректно отработало. Ладно, я как мидл за недельку-другую разберусь в любой архитектуре и заставлю всё работать как надо. Но джун такой проект точно не потянет.

Я не первый раз вижу, что синьоры переусложняют архитектуру, чтобы соответствовать принципам SOLID, CLEAN и т.д., но забывают что этой архитектурой будут пользоваться джуны, которые могут и не понять как всё это работает. И если для больших приложений (банков, маркетплейсов и т.д.) это оправдано, т.к. разрабу дают обычно ограниченный модуль, в рамках которого он делает свои задачи. То для небольшого и среднего приложения такое усложнение архитектуры считаю избыточным. Для большинства проектов достаточно MVP/MVVM + Repository

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

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

Публикации