Pull to refresh

Comments 45

На самом деле посыл статьи не о «хорошей практике» в создании архитектуры, а о практике, применимой в частных случаях. Абстрагирование от конкретных платформ неизбежно порождает ещё один набор промежуточных сущностей. И одна из задач архитектора как раз и состоит в том, чтобы решить — целесообразно ли в рамках проекта эти сущности плодить, или требования и перспективы проекта таковы, что выгоднее «прибить гвоздями» логику к платформе.
Многие «архитекторы» просто не видят этих сущностей над БД или JVM, о том «боль» автора, ИМХО. А использовать привычный технологический стек, конечно, не возбраняется, нужно лишь думать таким образом при разработке системной архитектуры, будто этот стек неважен.
> нужно лишь думать таким образом при разработке системной архитектуры, будто этот стек неважен.
Да не получится так думать на самом деле. Это допустимо лишь в том случае, когда переносимость — изначальное бизнес-требование к проекту. Во всех остальных случаях ответ на вопрос «что к чему прибивать гвоздями» всегда имеет численное выражение в человеко-часы и деньги, и должен быть решён одним из первых, на самых ранних этапах проектирования.
Ну, возможно, поймешь лет через десять… Если не перейдешь в менеджеры. :)
Поздно уже. Я прошел этап, когда писал программы на коленке, а вечером играл в третьих героев, прошел этап, когда я всерьез относился ко мнению падавана в этой статье, прошел этап, когда я всерьез относился к созданию гибких архитектур, и теперь я понимаю, что из всего этого лучше всего было играть в третьих героев.
Но этап, на котором «точно знаешь» этапность своего жизненного пути и заранее предполагаешь тот объём знаний, который ещё только будет освоен в будущем, возможно, ещё не пройден. Вы сами заговорили о себе, я просто поддержал беседу в ироничном ключе автора статьи, ничего личного (сам я на этапе третих героев пока). :)
Естественно. Возможно, в восьмых «героях» меня ждет откровение (хотя и маловероятно). Но вот от гибкой архитектуры я его уж точно не жду :)

Такая архитектура нужна не только для переносимости между платформами. Пример из своей области (Android) — нужно какую-то ленту новостей отображать. Клепаешь что-то на коленке. Чтобы побыстрее выкатить MVP кэширование в базу не впиливаешь, а каждый раз подгружаешь с инета. Но потом таки наступает момент, когда и кэш можна уже впилить, — а у тебя GUI знает, что данные с инета идут. Вот тут ты и попал.

Я же не говорю, что эта архитектура не нужна :) Я говорю, что её нужно применять не «by default», а осознанно, взвесив все «за» и «против», и определившись с инструментарием на самом раннем этапе проектирования.
А потом появляются нытики, которым изначальный выбор %DATABASE_NAME% не подешел, а прямо сейчас уже поздно что-то менять и приходится жрать кактусы.
Нытики есть и будут всегда, но простая истина заключается в том, что не бывает «бесплатной гибкости». Если у вас, реортически, %DATABASE_NAME% можно поменять, а на пректике — там всегда MySQL, то по прошествии 10 лет шансов на смену базы всё равно нет, а затраты на поддержку абстракции — есть.

YAGNI — очень хороший принцип, чесслово. Добавляйте гибкость там, где вы точно знаете когда вы будете её использовать. Если у вас в следующем релизе запланировано кеширование данных с бекенда — дело одно, а если вы это закладываете «на всякий случай» — совсем другое.
которым изначальный выбор %DATABASE_NAME% не подешел

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


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


Ну то есть если для конкретной задачи ваша база данных не подходит — это не повод "менять все", это лишь повод поставить рядом ту что подходит и как-то решить проблему малой кровью. Когда все "прибито гвоздями" это будет дороже, а когда есть пространство для маневра (DAO, Table Gateway, Data Mapper) — все довольно легко решается. Ну а если база данных не подходит для доброй половины задач — ну явно что-то не так пошло. Значит разработчик не разобрался зачем оно ему надо. И сейчас это проблема — многие берут тулзы не потому что они им нужны — а потому что в тренде все.


А всего-то надо разобраться с простейшей идеей разделения ответственности. И жить станет проще.

Эти сущности плодятся для того, чтобы выбранная платформа не диктовала как строить приложение. Иначе ядро программы («бизнес-логика») размажется ровным слоем по выбранным фреймворкам и станет надстройкой, а не полноценной и отдельной сущностью.

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

> С временем жизни проекта количество платформ может увеличиться
> Ядро программы может вообще пережить выбранную платформу.
А может и не увеличиться, а может и не пережить. И у кросс-платформенного решения есть своя цена. Причём она может выражаться не только в упомянутых выше деньгах и человеко-часах. Это может быть и цена производительности решения, и его масштабируемости, и его сроках выхода на рынок. Поэтому я не могу утверждать, что такая архитектура лучше или хуже. Всё, что я могу утверждать — что сначала надо делать оценку, а потом решать, подходит она конкретно для вашего проекта, или нет.
Ядро программы может вообще пережить выбранную платформу.

А еще ядро может исчезнуть. Микросервисы нынче в тренде и все такое. Бац так и нет ядра — распределенное приложение со всеми плюсами и минусами.

Стильно, творчески, понятно. Спасибо, очень понравилось, не сухо.
От себя внёс бы правку вместо реплики «Ну, возможно, поймешь лет через десять» привёл бы пример про недостаточность данных в начале разработке. Когда просят одно, а потом оказывается, что это немного другое. Или пока идёт разработка бизнес логика может измениться (например, вслед за потребностями рынка). И поэтому следует принимать эти решения, намного позже и делать всё оптимально гибко.
Требований всегда два: программа должна работать и быть готовой к изменениям.

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

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

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


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


Так же есть еще такая штука… вот вроде взять и изолировать работу с базой в отдельном объекте (gateway) — это не сложно. Это не то что бы сильно дольше, и это не требует каких-то глубоких познаний в программировании. Но "размазать по контроллерам же проще". Нет у людей понимания что проще — это когда мысль заложенная кодом прослеживается явно. "Простые" решения частенько приводят к "сложным" проблемам.


Ладно… я походу упоролся… но мне кажется вопрос сложности в ПО крайне интересным потому как я часто замечаю среди неопытных разработчиков извращенную трактовку сложности.

Многовато воды. 15 реплик, прежде чем привести пример кода, вместо того, чтобы сразу сказать "интерфейсы!"


А при проектировании "архитектором" интерфейса хранения данных неплохо бы иметь в виду какой-нибудь вариант реализации (опыт использования конкретных СУБД или создания файлового хранилища), чтобы знать, что придуманный интерфейс реализовать можно.
Иначе может получиться, что интерфейс-то есть, реализацию написали, а использовать систему нельзя — слишком плохо/медленно/etc всё работает из-за интерфейса, который в принципе нельзя реализовать эффективно.
Ещё опасно надеяться на то, что где-то есть реализация нужных фич (функциональности/надёжности/скорости), или что эти фичи как-то можно реализовать, не зная наверняка, как.


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

Могу предположить, что так не бывает, хотя к этому и надо стремиться.
Информация поступает уже после реализации. Иногда поступает такая информация, что приходится выкидывать все интерфейсы, реализацию, клиентский код и горе-архитектора, чтобы переписать всё нормально, чтобы этим можно было пользоваться.
До следующей подобной итерации. Это немного печально, но в этом суть ПО — его (как правило) можно переписать.

В практической области это означает, что наиболее опытным программистам следует поручать разработку инструментальной части, т.е. создание проблемно-ориентированного фреймворка
Автора покусали джависты. Если уж начал рассказывать о независимости подсистем — надо было делать это на примере очередей сообщений, AMQP или ZeroMQ, микросервисов. А то «зафиксируем тут у нас Java, интерфейсы, SQL — а дальше будем потом что-то решать». Что вы там уже будете решать, если зафиксировали язык, платформу, тип БД. Вам уже на этом этапе всё продиктуют традиции, обстоятельства и безысходность.

В идеале, да.
С другой стороны, делать полностью независимые от платформы/языка подсистемы — это ещё более "java-way" (очень суровый энтерпрайз, в смысле). Может получиться слишком абстрактно для обучения. Да и для жизни тоже.

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


да и не умея писать нормальные монолиты микросервисы делать не стоит. Проблем будет больше.

Рахим, какая прелесть! Прямо порадовал таким переводом. Давай еще :-) Дядя Боб рулит, впрочем, как и всегда.
UFO just landed and posted this here
> Как, ну как, можно заложить логику или платформы на весь жизненный цикл fb или aws?
Вы просто не учитываете тот момент, что зачастую изменения можно, а иногда и нужно игнорировать. Да, работая с каким-то вендорским сервисом, вам деваться некуда — это будут решать за вас, и вам для вашей же безопасности потребуется прослойка, которая абстрагирует вас от изменений API (насколько это возможно). Но если речь идёт, например, о СУБД или какой-либо библиотеке, то тут у вас уже больше вариантов для манёвров. Нередко оказывается, что ценность ПО и/или обрабатываемых им данных на порядки выше, чем ценность миграции на новые версии. И в таких случаях, например, может быть правильнее пожертвовать переносимостью в угоду стабильности ядра приложения.
UFO just landed and posted this here

Если можно — Oracle или MS, мне тоже интересно послушать.

UFO just landed and posted this here
> Кроме вендорского сервиса еще есть простой человеческий фактор, когда команда платформы,
> даже самой совершенной платформы
Я по этому поводу с вами совершенно согласен… но от этой проблемы, в общем-то, механизма защиты вообще нет. У лидеров проектов с взаимозаменяемостью крайне плохо. Если команда очень большая, и можно выдвинуть нового лидера, считай, повезло.
UFO just landed and posted this here
> Вопрос навскидку, сколько вы думаете СУБД поддерживает 1С: Предприятие?
Вы, на самом деле, приводите отличный контрпример :) Это система, которая была изначально жестко привязана к одной файловой нативной СУБД. И когда пришло время и спрос, её «отвязали» и дали возможность использовать другие СУБД.

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


Базы данных — так же. Нет смысла полностью от них абстрагироваться, но отделять логику от оных — вполне. То есть банальный DAO решает проблему так же как и data mapper или active record (да да, если обернуть data-model в обертку предоставляющую объектную модель, что-бы наша бизнес логика использовала active record тупо как атрибуты, то тогда все хорошо и плохо только с точки зрения юнит тестирования, и то есть варианты).


Менять базы данных никто обычно не планирует. А вот добавлять еще — это можно. Вполне может возникнуть ситуация при которой придется хранить часть данных в другой СУБД которая просто эффективнее справляется с задачей. А еще есть CQRS что бы творить вообще магические вещи. А еще — Event Sourcing что-бы совсем абстрагироваться от хранилища (на запись во всяком случае).


У того же FB есть проблемы с "прибитыми гвоздями" решениями. Часть они решают (HHVM, Hack вместо php), часть — нет (long polling вместо websockets) ну и т.д. Но у них и ресурсов побольше и задачи другие.


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

Есть некоторое недопонимание у комментирующих.


Эта архитектура не про про переносимость.
Эта архитектура позволяет откладывать принятие решений.


Вы начинаете разрабатывать ваше приложение(бизнес логику) и постепенно формируете требования, например, у хранилища должны быть транзакции, нужна возможность полнотекстового поиска. Так вы сформулируете абстракцию хранилища. Естественно, вы будете оглядываться на существующие решения или их комбинации.


Эта архитектура про независимость от реализации, а не про независимость от абстракции. Еще раз: ядро будет зависеть от абстракции.


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


Т.к. ядро зависит от MySQL-подобной абстракции, то не получится просто так перейти на другую абстракцию вроде Key-Value или EventSourcing.


Аналогично можно сказать и про UI и про все остальное.

UFO just landed and posted this here

Я имел ввиду, что есть абстракция(интерфейс) "Ноги": "левую вперед", "правую вперед", и т.д.
А какие конкретно ноги — это приходит извне.


Это не тоже самое, что абстракция "Перемещатель". Где у "Перемещателя" есть метод переместить в точку. А "перемещателелем" могут быть и ноги и машина и самолет.


Соответственно, эта архитектура о том, что вы знаете, что вы управляете "Ногами", но какими именно не знаете.

UFO just landed and posted this here

https://8thlight.com/blog/uncle-bob/2011/11/22/Clean-Architecture.html


Is this a perfect scheme? Of course not. Might one kind of UI be so different from another that they couldn’t share a common interface? Of course that’s possible. Does that mean this kind of decoupling is a waste? Are you kidding me?

https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html


The overriding rule that makes this architecture work is The Dependency Rule. This rule says that source code dependencies can only point inwards. Nothing in an inner circle can know anything at all about something in an outer circle. In particular, the name of something declared in an outer circle must not be mentioned by the code in the an inner circle. That includes, functions, classes. variables, or any other named software entity.

Никто не заставляет вас делать "универсальную абстракцию" БД или UI. Просто нужно сделать так, что бы БД или UI были плагинами к ядру. Естественно, этот интерфейс/абстракция располагается в ядре. Значит, этот интерфейс должен удовлетворять требованиям проекта. Если приложение работает с таблицами, то естественно, ему не подойдет Key/Value хранилище.

ну то есть инверсия зависимостей. То что наши классы реализующие работу с хранилищами завязаны на конкретной базе данных — это нормально если логика абстрагирована от конкретного хранилища интерфейсом. Простые примеры — Dao, Table Data Gateway и т.д. Или то что UI у нас завязан на приложении — это нормально. Как никак изменения в логике полюбому вызывают изменения в UI или хранилище (в пределах разумного конечно). А вот изменения в UI никак не должны сказаться на логике работы приложения.

UFO just landed and posted this here
Статься понравилась, но начинающим архитекторам может показаться что использование интерфейсов решат их все проблемы. А ведь есть много разных архитектурных паттернов. Есть общие архитектуры, а также внутренние.
И в совокупности всего этого можно получить хорошую архитектуру которая не только гибкая, ускоряет процесс разработки, имеет стандартные архитектурные паттерны, то есть новый разработчик быстрее вольется в разработку. Все это я к тому что архитектура может и должна выдавать не только гибкость.

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

Sign up to leave a comment.

Articles