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

Если не читали первую часть, настоятельно рекомендую это сделать, чтобы оставаться в контексте.

Итак, продолжим.

На чем мы остановились?

Мы начали с более дорогой структуры:

И смогли убрать небольшое количество компонентов.

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

За что мы платим?

Разрывы связей

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

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

Структура, которую мы будем использовать для следующего примера — это APIImpl. В этой структуре Api‑модуль — интерфейс фичи, в котором предоставляется доступ к компонентам для переиспользования. За реализацию фичи и всех её компонентов отвечает Impl‑модуль.

Вот варианты предоставления доступа к UseCase, к Repository и к обоим компонентам сразу:

Если структура feature-shared резала общую часть вертикально, то API-Impl нарезает её горизонтально (относительно текущей формы представления схем).

Видно, что для данной структуры снова появляются интерфейсы в Repository, а также дополнительно появляются интерфейсы в UseCase в зависимости от общей части.

Давайте разберёмся, зачем они нужны.

Может показаться, что API-модуль с интерфейсами используется для инверсии зависимостей. Действительно, в редких случаях такая структура позволяет решать архитектурные задачи при помощи инверсии зависимостей, но в рамках взаимодействия разных feature-модулей. В любом случае, считать это самоцелью данной структуры — абсолютно неверно.

Особенность и сильная сторона структуры API-Impl заключается в условии, что Impl-модули не должны зависеть от других Impl-модулей. Это условие помогает в обеспечении принципа ацикличности зависимостей (Acyclic Dependencies PrincipleADP). А также мы избавляемся от проблемы структуры feature-shared, когда изменения в реализации shared-модуля приводили к необходимости пересобирать все зависимые части.

Интерфейсы в Repository и UseCase отсутствуют в тех ситуациях, когда нет необходимости делать их логику общедоступной.

Но это всё предисловие, а разговор должен был идти про какие-то связи.

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

Количество связей и компонентов не меняется, но при этом анализировать код в контексте конкретной фичи становится проще. 

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

Опциональные компоненты

1. Шаблоны проектирования

Мы можем поменять шаблон проектирования внешнего архитектурного слоя с Model-View-Presenter (MVP) на Model-View-ViewModel (MVVM) или на Model-View-Intent (MVI):

Из-за своей особенности шаблону MVP необходим был дополнительный компонент для инверсии зависимостей и обеспечения направления зависимостей обратно потоку выполнения. Говоря проще, Presenter напрямую указывал View, что делать, но не зависел от ui-слоя.

У MVVM и MVI таких особенностей нет, и нужное направление зависимостей обеспечивается по умолчанию.

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

2. Конвертация

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

Главное, чтобы Entity при этом оставалась чистой и не содержала никаких упоминаний о модели (DTO), которую нам присылает бэкенд.

Экстремальная экономия

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

Лишние проксирования

1. Проксирующие DataSource-ы

Сначала рассмотрим, для чего нужен был DataSource. Как компонент источника данных, он был необходим для выноса логики по настройке источника. Так мы отгораживаем Repository от платформенной или сторонних зависимостей.

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

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

В Android мы используем Retrofit, с помощью которого можно сократить количество настроек до минимума, а при хорошем подходе можно сократить этот минимум до одного интерфейса API с настройками в аннотациях для конкретных ручек. В итоге компонент DataSource для удалённых источников данных будет служить нам только для проксирования методов API. Почему бы нам не избавиться от него, как от лишнего компонента в случае работы с удалёнными источниками?

Но для локальных источников этот компонент будет всё-таки нужен. Например, в тех случаях, когда мы захотим получать данные удалённо и сохранять их в Preferences, необходим будет Context для настройки этих Preferences:

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

  1. Проксирующие UseCase-ы

При должном проектировании наличие бизнес‑логики для тонких клиентов — явление редкое. Это даёт нам повод рассуждать об опциональности UseCase‑ов, которые очень часто выступают проксирующими классами.

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

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

И куда нас это привело? Снова к Чистой Архитектуре!

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

Схема из статьи «Заблуждения Чистой Архитектуры»

Но результат экономии отличается своей линейностью:

Линейное направление зависимостей
Линейное направление зависимостей

И выглядит теперь так:

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

Нет! Мы пришли к ЧА, чтобы обеспечить масштабируемость!

Полагаю, что с того момента, как был поставлен вопрос «Что делает ЧА дорогой?», мало кто из читателей задался вопросом — «‎А как все компоненты, на которых мы сэкономили, относятся к ЧА?».

Кроме UseCase, для мобильной разработки ни один из убранных компонентов не был обусловлен ЧА. Да и он в книге был упомянут таким же опциональным, когда Дядя Боб говорил, что этот набор слоёв не является обязательным. Однако я не считаю отсутствие UseCase равносильным отсутствию слоя. Как только бизнес‑логика появится, появится и соответствующий компонент. А значит слой есть, просто он временно бедствующий ждёт своего часа.

До этого момента я слышал только 2 мнения:

  • ЧА — это плохо потому, что дорого.

  • ЧА — это хорошо, хоть и дорого.

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

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

Дядя Боб не был мобильным разработчиком.

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

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

Любые изменения в API бэкенда могут привести к тому, что нам придётся менять все слои, чтобы эти изменения поддержать. Что нам это напоминает? SDP: «устойчивым компонентом является тот, изменяя который вы не сможете избежать изменения в остальных компонентах». Получается бэкенд является главным направлением устойчивости для тонких клиентов.

Как бы сильно мы не делали вид, что это не так, как бы много интерфейсов не нагородили, мы всё равно обязаны будем поддерживать все эти изменения. Например, если для одной из ключевых Entity добавилось обязательное поле, отложенное решение по нему можно принять на всех слоях без потери работоспособности приложения. Можно просто не добавлять поле, пока вы не захотите отобразить его. А когда захотите, его придётся поддержать на всех слоях. Можно делать это постепенно, но начиная от data-слоя, а не от domain.

Другой пример: если обязательное поле исчезнет из Entity и старый API перестанут поддерживать, нам придётся в срочном порядке применять эти изменения на всех слоях.

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

Единый продукт

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

И расширим границы до представления единого продукта:

Схема абстрактная, а наличие БД и внешних зависимостей для бэкенда на ней опущено для лучшей концентрации на взаимодействии с клиентами, но они всё еще есть в наших сердцах в рамках структуры бэкенда. Также Entities для клиента и бэкенда редко совпадают настолько, чтобы на схеме они стали общими.

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

Вывод

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

Важно понимать, что мы не стремимся насильно уменьшить количество компонентов под эгидой экономии, перекладывая логику одного слоя на другие. Компонент UseCase-а стал опциональным, но не исключён из структуры в тех ситуациях, где он действительно нужен. Равно как для структуры API-Impl интерфейсы в Repository и UseCase остаются опциональными и необходимы в ситуации, когда код должен быть общедоступным.

А в заключение хочется отметить несколько важных для понимания моментов:

  1. Слои не так важны, как компоненты, из которых они сложены.

Наличие слоёв, перечисленных автором, не является необходимым для обеспечения чистоты архитектуры. Важно уметь обращаться с теми компонентами, из которых состоит ваша архитектура. Из них вы выстраиваете необходимые для вас слои. Если компонент сам по себе бесполезен и нужен для формального существования слоя, то это вредит масштабируемости.

  1. Зависимости зависят от устойчивости.

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

  1. Устойчивость не равна редкой изменяемости.

Не тот компонент устойчив, что редко меняется, а тот, меняя который придётся поддержать изменения на всех слоях. Эта мысль взята из книги ЧА. Но считаю важным лишний раз её озвучить.

  1. Интерфейсы ситуативны.

Повторюсь, что в своей книге Мартин упоминал необходимость интерфейсов в двух случаях:

  • Чтобы отгородиться от платформы или иных внешних зависимостей.

  • Чтобы реализовать инверсию зависимостей и обеспечить их направление в сторону устойчивости.

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

  1. Чистота — это свойство.

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

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

  1. Чистая Архитектура дешевле, чем её представляют.

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

На этом всё. Спасибо за уделённое время и что осилили до конца!

P.S. Управляйте зависимостями, оставайтесь независимыми.

Комментарии (12)


  1. kozlov_de
    22.03.2024 13:44

    хорошо бы вы написали так:

    вот предлагаемая архитектура (включая и клиент и сервер)

    проверим, насколько она хрупка

    вот компонент на сервере, который часто/редко меняется и при его изменении понадобится изменить эти компоненты на сервере и эти на клиенте

    на самом деле, не так и много компонент на сервере потребует изменений компонент на клиенте и обратно

    тут скорее будет API first (контракт, для которого понадобится и изменения на клиенте и на сервере), когда и клиент и сервер должны реализовать этот API

    только вот картинка будет некрасивая


  1. gal_may
    22.03.2024 13:44
    +1

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


    1. Artilirium Автор
      22.03.2024 13:44
      +2

      Чистая Архитектура это та архитектура которую мы называем Чистой

      Не уверен, что это взято на основе этих статей.
      Как мне казалось, в первой части термин был выведен чуть более четко :)

      Она улучшилась или ухудшилась?

      Улучшилась.

       На сколько?

      Если говорить про субъективные ощущения, то достаточно сильно, чтобы написать об этом статью :)
      Если говорить про цифры, то устранение компонентов, перечисленных в первой статье и части компонентов из второй, увеличило ТТМ фич до 2 штук в 2 недели (за спринт) на моей позапрошлой работе, в команде из двух разработчиков на проекте, в котором было 60+ разработчиков.
      До этого была фича в неделю, стало быть улучшилось примерно в 2 раза.
      Закрепление этих практик на следующей работе также показало положительную динамику, но я уже был не в фича-команде. К сожалению не могу ссылаться на метрики прошлой работы, но таковые велись и они существенно улучшились.
      Методы из экстремальной экономии ввелись в дополнение к остальным практикам на текущей работе и применяются во всей совокупности относительно недавно, потому и использовал слова "время покажет".
      Думаю можно было применить эти слова не ко всей совокупности, а лишь к той её части, которая ввелась недавно. Моя ошибка.
      Но за то время, что мы применяем всю совокупность, могу смело сказать - "5 минут, полёт нормальный!".

      Сколько файлов теперь надо поменять для добавления новой фичи?

      В зависимости от фичи. От 5 классов и более.
      Если откатываться назад и возвращать лишние компоненты, то минимальное количество было бы пропорционально больше.

      Что и с производительностью стало?

      Если говорить про производительность приложения в Runtime, то, ожидаемо, отсутствие лишних компонентов не скажется никак. Обфускатор под капотом в любом случае срезал бы их количество.
      Если говорить про Build Time, то мы получили положительную динамику в совокупности с преимуществами применяемой структуры.
      В сравнении с оптимизациями gradle, цифры, разумеется, не такие внушительные, чтобы рассматривать сокращение Build Time, как цель.
      Целью преследовалось улучшение масштабируемости проекта и сокращение ТТМ, но про него я уже сказал в этом же комментарии выше.

      Багов больше или меньше стало?

      К сожалению нигде не велась статистика на подобии "bug per minute". Полагаю, что в убранных проксирующих компонентах и интерфейсах сложно было бы заложить баги в принципе.

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

      ___________
      Спасибо за ваши вопросы!


      1. gal_may
        22.03.2024 13:44
        +2

        Не уверен, что это взято на основе этих статей.
        Как мне казалось, в первой части термин был выведен чуть более четко :)

        Цитата:

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

        и далее

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

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

        Если говорить про цифры, то устранение компонентов, перечисленных в первой статье и части компонентов из второй, увеличило ТТМ фич до 2 штук в 2 недели (за спринт) на моей позапрошлой работе, в команде из двух разработчиков на проекте, в котором было 60+ разработчиков.

        Вот это уже интереснее, правда это не про масшатбируемость и я не понял причем тут 60+ разработчиков, если метрика про двух, но да ладно. Т.е. раньше два разработчика делали одну фичу за спринт, то теперь могут делать две за спринт.

        Закрепление этих практик на следующей работе

        Тут опять надо бы конкретику: сколько было, сколько стало, сколько удалили... Но это скорее другая статья ;)

        Но за то время, что мы применяем всю совокупность, могу смело сказать - "5 минут, полёт нормальный!"

        5 минут не считается.

        В зависимости от фичи. От 5 классов и более.

        Извините, но это какой-то странный ответ. 5 классов это много или мало? А было сколько?

        Обфускатор под капотом в любом случае срезал бы их количество.

        WAT? Это как?

        Если говорить про производительность приложения в Runtime

        Тут много что можно смотреть и мерять: рендеринг, время старта, память, батарейку, сеть и тп

        К сожалению нигде не велась статистика на подобии "bug per minute"

        Very nice code quality management. Вы в VK работаете да?
        Я имел ввиду количество багов на 100 строк кода, например. Вы же удалили код, значит метрика должна была улучшиться, так? Можно чуть шире посмотреть, например на тестовое покрытие, которое тоже может улучшиться, когда удаляют код.

        сокращением количества багов обусловленную большей концентрацией разработчиков 

        Хз. Мне кажется тут прямая зависимость. Чем больше разработчиков, тем больше багов. Разработчики источник багов жеж.

        ----------------------------

        Да, я сегодня "токсик" и заноза в заднице. Пятница жеж :))


        1. Artilirium Автор
          22.03.2024 13:44
          +1

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

          Приведённые вами цитаты отвечают не на вопрос, "что такое ЧА"

          Определение ЧА было в первой части статьи.
          Из определения важно было понять, что "чистота" - это свойство.
          Также была приведена характеристика, на которую оно влияет.

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

          правда это не про масшатбируемость и я не понял причем тут 60+ разработчиков, если метрика про двух, но да ладно

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

          Также, если двое человек поставляли по 2 фичи в месяц на проекте - это не значит, что через 5 лет этот показатель сохранится. Тут идёт зависимость от увеличения количества строк в кодовой базе.

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

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

          ЧА должна без проблем усвоить увеличение количества разработчиков и увеличение строк кода в кодовой базе с течением времени.

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

          5 минут не считается.

          Мне показалась данная метафора уместной. Будто бы масштабный проект это ракета, 5 минут полёта которой без отклонений - это существенный результат, но радоваться пока рано. Мы затаили дыхание в надежде, что всё и дальше будет хорошо :)

          WAT? Это как?

          Извиняюсь, моя ошибка. Хотел написать более развёрнутый ответ про совокупность компилятора и обфускатора, потом подумал, что упомянуть про оптимизацию компилятором будет достаточно для ответа. Только вот удалил я не то. Сами понимаете, пятница :)

          В общем компилятор всё равно проводит оптимизации для релизных сборок. В том числе оптимизацию вызовов. Соответственно под нож оптимизации подпадут проксирующие.

          Тут много что можно смотреть и мерять: рендеринг, время старта, память, батарейку, сеть и тп

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

          Всё таки мы говорим про архитектуру приложения, а не аппаратных компонентов.

          BuildTime улучшится в том числе и из-за облечения работы компилятору (меньше компонентов - меньше работы).

          Про TTM уже говорил

          Very nice code quality management. Вы в VK работаете да?Я имел ввиду количество багов на 100 строк кода, например. Вы же удалили код, значит метрика должна была улучшиться, так?

          Будь то "bug per minute" или "bug per row", это всё неизмеримые характеристики. Если бы внесении кода в проект все отчитывались о количестве багов в нём,, то зачем они вообще вносили этот код?
          Да и "баги на 100 строк кода" можно было бы размывать бесполезным кодом. Так сказать снизить концентрацию багов, но не их количество.

          Но если вас интересует именно метрики, то могу предложить Crash-Free. Этот показатель улучшался на протяжении удаления лишних компонентов.
          Но если говорить именно о падениях на нашем проекте, то сложно оценить, насколько экономия повлияла на уменьшение их количества.

          То, насколько уменьшиться именно количество багов, существенно зависит от начальной структуры.
          Если никакой структуры не было, то влияние будет колоссальным.

          Можно чуть шире посмотреть, например на тестовое покрытие, которое тоже может улучшиться, когда удаляют код.

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

          Хз. Мне кажется тут прямая зависимость. Чем больше разработчиков, тем больше багов. Разработчики источник багов жеж.

          Чем больше разработчиков или чем больше кода?
          Если дать разработчику время, чтобы написать столько же кода, сколько написали 10 разработчиков, внесёт ли он меньше багов, чем они? Зависит от навыков разработчика.

          Сильно дискуссионная тема, чтобы пытаться её развивать в комментариях.
          Зато тема богатая на шутки :)

          Да, я сегодня "токсик" и заноза в заднице. Пятница жеж :))

          Наоборот, круто, что есть вопросы! Значит тема интересная.
          Меня это радует :)

          ___________
          Спасибо за ваши вопросы!


        1. Artilirium Автор
          22.03.2024 13:44
          +1

          случайно пропустил пару вопросов

          Извините, но это какой-то странный ответ. 5 классов это много или мало?

          Много или мало - субъективная оценка.

          Указал количество для разработчиков, чтобы каждый мог сравнить с собственным количеством и самостоятельно оценить.

          А было сколько?

          Для структуры из первой схемы минимум соответствует количеству компонентов на ней - 13.


          1. gal_may
            22.03.2024 13:44
            +1

            Я попробую по-коротче, т.к. многое в вашем ответе просто мелочь.

            Много или мало - субъективная оценка.

            "много" и "мало", действительно, субъективная оценка, а вот 5% и 10% - нет. О чем и был вопрос. Абсолютные цифры редко бывают информативны, когда объемы постоянно меняются. Вы бы знали это, если бы действительно измеряли этот параметр.

            Приведённые вами цитаты отвечают не на вопрос, "что такое ЧА"

            Приведенные цитаты это ваш вывод в статье. И я с ним абсолютно согласен - ЧА это просто культ имеющий мало связи с реальностью. Бессмысленно рассуждать об архитектуре в отрыве от задач, которые нужно решить. Не существует кода, который хороший или плохой сам по себе, сложно даже сказать корректный код или нет, если мы не знаем какую задачу он решает, но адепты "культа ЧА и SOLID" почему-то считают по-другому. У них, почему-то, существует сферическая (а она действительно сферическая, судя по картинкам) архитектура в вакууме (и она, действительно, в вакууме, т.е. оторвана от реальности, как следует из диалога с Кейси https://github.com/unclebob/cmuratori-discussion/blob/main/cleancodeqa.md и критики Кейси же https://www.youtube.com/watch?v=tD5NrevFtbU). Ладно, мы слегка отклонились.

            В книге хорошо описана ситуация, из которой видно, что увеличение количества <и далее. я все не стал цитировать>

            Да, увеличение числа разработчиков это про масштабирование, но вы-то ответили про TTM Цитата: <увеличило ТТМ фич до 2 штук в 2 недели (за спринт) на моей позапрошлой работе>.
            Что же до SRP, то это самоочевидный принцип еще со времен LISP и рассуждений о чистых функциях, к ЧА он имеет отношение постольку-поскольку, со всеми же недостатками, которые ЧА игнорирует.

            Будь то "bug per minute" или "bug per row", это всё неизмеримые характеристики.<...>

            Seriously? Баги напрямую влияют на потребительские свойства продукта, а вы их не измеряете?

            Меня интересует что вы оптимизируете и как вы это измеряете. Или у вас архитектура ради архитектуры?
            Размытие кода "бесполезным кодом" во-первых ухудшит производительность разработчиков, т.к. на бесполезный код надо тратить время, во-вторых есть вполне реальный шанс что в "бесполезном коде" тоже будут баги, в-третьих вас уволят быстрее чем вы увидите разводнение :). Если же в бесполезном коде нет багов, то я бы присмотрелся как это так людям удается писать код без багов. ;)

            Если никакой структуры не было, то влияние будет колоссальным.

            вот и продемонстрируйте это на реальном примере.

            Сильно дискуссионная тема

            Абсолютно нет - разработчики ЕДИНСТВЕННЫЙ источник багов. Чем их больше, тем больше багов, независимо от их квалификации.

            Будто бы масштабный проект это ракета

            Масштабный проект это марафон - быть первым на первых 5 минутах ничего не решают.

            В общем компилятор всё равно проводит оптимизации<...>

            Первое, относительно итерфейсов и виртуальных вызовов, то компилятор, Proguard и R8 далеко не всегда делают коллапс, инлайнинг и статический вызов. Второе, оригинальная идея для введения интерфейсов была в том, что они, помимо полиморфизма, помогают изолированно тестировать компоненты. Как там с параметром Testability? Лучше? Хуже?

            К сожалению на них влияния не будет

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

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


            1. Artilirium Автор
              22.03.2024 13:44

              "много" и "мало", действительно, субъективная оценка, а вот 5% и 10% - нет. О чем и был вопрос. Абсолютные цифры редко бывают информативны, когда объемы постоянно меняются. Вы бы знали это, если бы действительно измеряли этот параметр.

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

              Для первой структуры был минимум 13 компонентов + 5 из них покрывается Unit-тестами.

              В последних примерах был минимум в 5 компонентов + 2 из них покрывается Unit-тестами.

              Возможно вы хотите услышать, как было удалено 11 лишних классов.
              Но если мы изначально использовать указанные структуры, то мне сложно будет презентовать информацию о том, как не было написано 11 лишних классов.

              Ну а дальше в дело вступает масштабирование по количеству featue. Если их у вас на проекте 100, то получаем экономию минимум в 1100 компонентов :)

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

              Предупреждая ваш вопрос. Нет, я не измерял, сколько минимальных feature в отношении к не минимальным :)
              Боюсь, что тут я полагался лишь на субъективные ощущения от опыта, когда работал в feature-команде :)

              Приведенные цитаты это ваш вывод в статье.

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

              Подписчики бегут в салон с автомобилями и говорят - "мы хотим чистый автомобиль!". Им предлагают на выбор всех цветов и оттенков.
              Они - "Это не чистые автомобили!". Находят глазами красный и говорят - "Это чистый автомобиль!".
              Настолько часто происходит такая ситуация, что продавцы, слыша слова "Чистый автомобиль", сами считают, что речь может идти только о красном.

              И в рамках этого примера ваши слова "культа ЧА", очень даже уместны, мне понравилось :)

              Я просто пытался сказать, что любой автомобиль может быть чистым.
              Тьфу ты.. Архитектура!

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

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

              Да, увеличение числа разработчиков это про масштабирование, но вы-то ответили про TTM

              А, теперь я понял о чем речь :)

              Да, я ответил про ТТМ в рамках масштабированного проекта по числу разработчиков и модулей. В предисловии было упомянуто про 300+ модулей и 60+ разработчиков.
              TTM, как основной показатель для архитектуры, не должен упасть. А в идеале должен расти при изменениях в ней. То, что показатель вырос примерно в 2 раза, в условиях этих количеств, я считаю отличным показателем того, что архитектура хорошо масштабируема.

              Seriously? Баги напрямую влияют на потребительские свойства продукта, а вы их не измеряете?

              Могу показаться наивным, но мы их фиксим, а не мерим :)
              Не уверен, что кто-либо может уверенно сказать точное количество багов на своём проекте. А сколько из багов - фичи? :)
              В плане метрик я предложил показатели Crash-Free, вроде как стандартная штука, да и мерить гораздо проще, т.к. обладает более точными критерями :)

              Меня интересует что вы оптимизируете и как вы это измеряете. Или у вас архитектура ради архитектуры?

              А, ну так вопрос более понятен. Мы оптимизируем время на разработку, как способ сокращения ТТМ.

              Размытие кода "бесполезным кодом" во-первых ухудшит...

              Да я ж рассуждал об абсурдности показателя "bug per row". О том, что оный был бы ярким примером фразы, что "есть ложь, гнусная ложь и статистика".

              вот и продемонстрируйте это на реальном примере.

              Я демонстрирую на примере старой структуры, максимально приближенной к той, к которой все стремятся, когда говорят о ЧА.
              Все примеры структуры взяты из реального опыта, просто с разных проектов.
              На схемах видно, что минимальное количество компонентов на фичу снизилось чуть больше, чем в 2 раза.

              Абсолютно нет - разработчики ЕДИНСТВЕННЫЙ источник багов. Чем их больше, тем больше багов, независимо от их квалификации.

              С этим я спорить не буду :)
              Но ставлю под сомнение вашу фразу "Чем больше разработчиков, тем больше багов".

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

              И вот это уже дискуссионная тема о разработчиках в вакууме и вне его :)

              Масштабный проект это марафон - быть первым на первых 5 минутах ничего не решают.

              Это верно, но я говорю про уже разогнавшийся проект. В архитектуре которого внесли определённые изменения не в первом году его жизни. При этом не потеряли скорости

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

              Понимаю, я бы мог сказать, что при условии, что компилятор не провёл этих оптимизаций, мы экономим на нескольких вызовах. Но это настолько незначительно, что говорить об этом не стоит.
              Влияния на Runtime не будет.

              Как там с параметром Testability? Лучше? Хуже?

              Об этом было в первой части статьи - нет изменений совсем.

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

              Моя вина, что не сделал дополнительного акцента в статье на это.

              Чуть выше уже ответил на подобный вопрос, что мы оптимизируем время на разработку, как способ сокращения ТТМ.
              ___________
              Спасибо за замечания!


  1. funca
    22.03.2024 13:44
    +1

    CA описывает архитектуру системы, а не отдельного компонента. Один из тезисов говорит про независимость от UI.

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

    Если ответ да, то изначальное желание затащить еще какую-то CA внутрь клиента, выглядит немного сюрриалистично.


    1. Artilirium Автор
      22.03.2024 13:44

      CA описывает архитектуру системы, а не отдельного компонента.

      Автор в книге регулярно использовал термин "компонент" то к классам, то к сервисам в целом. Всё зависело от того, о каком уровне абстракции он рассуждал в данный момент.

      Всё связано.

      Интересно, не является-ли такой клиент, в терминах данной архитектуры фактически тем самым UI, независимость от которого они хотят добиться?

      UI для клиента - такой же внешний слой архитектуры, как Api для бекенда.

      Можно ли сказать, что приложение - это UI?
      Думаю можно сказать, что телефон - это среда предоставления UI для сервиса в целом.

      Но само приложение - это не UI.

      Не смотря на всю тонкость клиентов, телефон является не только средой предоставления UI.

      На уровне клиентов можно организовать

      • кеширование;

      • взаимодействие с внешними сервисами, такими как пуши, локация и т.п.;

      • взаимодействие с аппаратными компонентами, такими как камера, Blutooth и т.п.;

      • эксперименты (особенно касающиеся UI слоя);

      • разного рода аналитику;

      • Feature-тоглы;

      • и т.п.

      К тому же не стоит забывать, что бекенд разработчиков не всегда хватает. Да и ситуации бывают разные. Иногда для MVP бизнес логика может утечь и в клиент.

      Также бизнес логика на клиенте может быть оправдана не только моментом.

      Т.о. мобильные клиенты стремятся быть тонкими, но это скорее стремление к идеалу.
      А значит архитектура нам всё еще нужна.
      ___________
      Спасибо за ваш вопрос! :)


      1. funca
        22.03.2024 13:44

        А значит архитектура нам всё еще нужна.

        Нужна-ли здесь CA или может быть какая-то другая архитектура?


        1. Artilirium Автор
          22.03.2024 13:44

          Для предисловия позволю себе скопировать пример из другого обсуждения выше

          Какой-то блогер говорит - "насколько же круто ездить на чистом автомобиле". И показывает свой чистенький красный автомобиль.

          Подписчики бегут в салон с автомобилями и говорят - "мы хотим чистый автомобиль!". Им предлагают на выбор всех цветов и оттенков.
          Они - "Это не чистые автомобили!". Находят глазами красный и говорят - "Это чистый автомобиль!".
          Настолько часто происходит такая ситуация, что продавцы, слыша слова "Чистый автомобиль", сами считают, что речь может идти только о красном.

          Если вы хотите купить автомобиль, то вы хотите, чтобы он был чистым:)

          Нужна-ли здесь CA или может быть какая-то другая архитектура?

          Нужна :)
          И да, это может быть "какая-то другая архитектура", нежели та, что приведена в примере из книги.

          ___________
          Спасибо за ваш вопрос! :)