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

Создание архитектуры программы или как проектировать табуретку

Время на прочтение25 мин
Количество просмотров696K
Всего голосов 88: ↑85 и ↓3+82
Комментарии45

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

НЛО прилетело и опубликовало эту надпись здесь
Спасибо за статью!

Могу только посоветовать в данном контексте обратить внимание на шаблон Делегат (Delegation/Delegate) и пришедший из игр шаблон Компонент (Component). Последний, к сожалению, описан только на английском, но зато очень детально.
Насчет шаблона компонент — есть перевод книги gameprogrammingpatterns, включая статью о нем:
live13.livejournal.com/473028.html
Спасибо! Ценное дополнение. Уже исправлено
максимально сопряженны внутри и минимально связанны друг с другом

Я не совсем уверен кто не прав. В Макконнеле(связность зацепление) эти понятия используются наоборот.

То есть минимальное сопряжение между модулями и максимальная связность внутри модуля.
Вы правильно заметили, что термины «Cвязность» и « Зацепление» часто вызывают путаницу. Связано это с неоднозначностью перевода. Дело в том что английские термины «Cohesion» и «Coupling» близки по смыслу и оба могут быть переведены, как связность/сцепление/зацепление. Соответственно, в зависимости от перевода, можно увидеть, что должна быть «низкая связанность и высокое зацепление» и наоборот — «высокая связность и низкое зацепление». Суть же заключается не в разнице между «связанностью» и «зацеплением», а в том где эти самые связность/зацепление должны быть максимальны и минимальны.

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

Чтобы избежать неоднозначности, лучше всего, конечно, пользоваться английскими терминами: High/Strong Cohesion inside, Loose/Low Coupling between.

А вот что пишет сам Макконел в оригинале:
«Strong Cohesion. Cohesion refers to how closely all the routines in a class or all the code in a routine support a central purpose—how focused the class is.»

«Loose coupling means designing so that you hold connections among different parts of a program to a minimum.»



Возможно будет полезна следующая грубая, но наглядная аналогия. Представте, что есть система, состоящая из множества деталей соединенных проводами, и вам эту систему нужно разрезать/разделить на модули. Принцип “High/Strong Cohesion, Loose/Low Coupling” просто означает, что «резать» нужно там, где мало проводов. Так, чтобы максимальная концентрация проводов оказалась внутри модулей, а между модулями проводов было бы как можно меньше
Хорошая статья, интересные ссылки!
В конце просится абзац про микросервисы и архитектуру облачных приложений
А там есть какие-то особенности? Это дальнейшнее развитие этой идеи, наверхну у нас есть система, отдельные микросервисы выступают в роли компонентов системы, ну и дробим дальше.

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

а зачем им «синхронизироваться»? У каждого микросервиса своя зона ответственности. Если вы про кеширование на локальном уровне микросервиса — это уже оптимизации.

По организации взаимодействия все так же упирается в производительность. В большинстве случаев можно просто HTTP юзать, а в сложных случаях уже подключать какие-нибудь zeromq/kafka/rabbitmq + messagepack например.

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

1) Иерархичность декомпозиции. Про нее везде пишут, но она проходит мимо сознания. Тут какой-то психологический блок. Благодаря ООП мы привыкли думать и проектировать сразу на уровне классов/объектов. А это слишком мелкая декомпозиция. Необходимость создания архитектуры вроде бы подталкивает нас к тому чтобы систему вначале разбить на модули, но полученные в результате первичной декомпозиции крупные модули — «бизнес-логика», «представление», «база данных» на практике оказываются слишком крупными. Хотя и Мартин Фаулер и Макконел только их и относят к архитектуре. Фаулер в самом начале своей книги «Архитектура корпоративных программных приложений» так и пишет, что с термином архитектура связывают “разделение системы на наиболее крупные составные части”. Макконел же прямо дает алгоритм — делим систему на модули/пакеты, а пакеты сразу же делим на классы.

В результате такая простая и очевидная мысль, что большие первичные модули тоже нужно делить не на классы, а на подмодули, она как-то не приходит в голову. И вот как раз этот то разрыв между слишком крупными первичными модулями и слишком маленькими объектами и устраняет “архитектура микросервисов”. Архитектура микросервисов заставляет реализовать как минимум два уровня декомпозиции и, к примеру, модуль «бизнес логики» разделить на подмодули — «управление заказами», «управление клиентами», «платежи» и тд. Он помогает нам перейти от “думания объектами” к более эффективному “думанию и проектированию небольшими модулями-подсистемами” (то есть микросервисами)

2) Масштабируемость приложения за счет того, что любой модуль может быть запущен в любом количестве экземпляров. Это тоже вроде бы очевидная, но не всегда приходящая в нужный момент в голову, идея-техника, дающая возможность адаптировать систему под самые различные нагрузки, которая в «микросервисах» также очень хорошо выделена, сформулирована и “на блюдечке” доносится до нашего сознания. Она так и называется — «масштабирование за счет клонирования»
Добавление к разделу «Что почитать»: если Банда Четырёх покажется сложноватой, то можно начать с «Head First Design Patterns» от O'Reilly. Тоже очень достойная книга по шаблонам проектирования.
Я бы не рекомендовал ни GoF ни Head First Design Patterns как минимум потому, что разработчик может банально упустить суть. Эрик Гамма например считает что вреда от GoF вышло столько же, если не больше, сколько и пользы.

Вообще с паттернами вышло забавно, сначала появились они (94-ый год) а потом уже обоснование (GRASP в 2001 и примерно там же SOLID), хотя отдельные концепции из SOLID использовали еще в 60-х и 70-х, и по сути не привязаны конкретно к ООП.
Эрик Гамма например считает что вреда от GoF вышло столько же
А ссылку можно? Гуглится только, что он хотел бы только чуть отрефакторить книгу и добавить новые шаблоны.

Про SOLID. В статье об этом примерно и написано. Liskov/DI существуют давно, ISP по сути то же самое, что и SRP, а SRP и OCP это и есть основные способы достичь «loose coupling, high cohesion». Мартин нового ничего не придумывал, просто грамотно описал концепции.
А можете в таком случае порекомендовать что-нибудь более фундаментальное? SOLID, GRASP, вот это всё. То есть я знаю, что такое SOLID но хочется чего-то более объемного, чем статья на википедии — с примерами того как надо и как не надо, с какими-то смежными концепциями и так далее.
Всем, кому понравилась статья, очень рекомендую эту книгу: www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215. В ней затронута важная тема отделения «инфраструктуры» от «предметной области». А также вот эту: www.manning.com/books/specification-by-example. Во второй — про составление спецификации и внедрение гибких процессов.
Просится продолжение, а лучше цикл с практическими материалами.
По архитектуре приложений еще довольно объемный архив/набор книг/статей (смотря с какой стороны смотреть)
aosabook.org/en/index.html
Виноват, пропустил ссылку сюда же
НЛО прилетело и опубликовало эту надпись здесь
Читал и плакал. В компании где я работаю, а конкретно в моем отделе (PHP), от таких слов как «interface, solid, unit test, patterns» в меня летят камни… Любой функционал или проблема решается смесью:

1. добавления нового флага в метод/функцию
2. созданием новой глобальной константы
3. добавлением новой функции в мегафайл functions.php
4. тупо еще один if куда нибудь из предидущих пунктов и все счастливы

И это только верхушка айсберга…

Я пока воюю, так как за плечами JAVA/C# OOP, да и PHP немало лет… ну и инженерное образование… но на сколько меня хватит. Главная отмазка — нам надо быстро… Если я кину всем почитать эту статью, меня убьют… а жаль.
Главная отмазка — нам надо быстро…

Быстро зафэйлить проект? А вы попробуйте посчитать экономическую эффективность всех этих «ругательных слов». Для начала постарайтесь снять следующие метрики:

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

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

Если же у вас в голове есть план как сократить издержки за счет налаживания процессов — ну тогда можно идти к менеджменту и говорить о том что «мы можем сэкономить вам за год столько-то денег если сделаем то-то то-то». А дальше — это уже проблема менеджмента.
Аргументируйте свою позицию ссылками на авторитетные книги, статьи классиков проектирования. Если же в компании даже не знают про таких «авторитетов», то значит пытайтесь просветить людей докладами, примерами. Если же ничего не помогает, это значит, что люди не хотят профессионально развиваться — в такой компании я бы не стал задерживаться.
Я бы добавил еще одну ключевую разницу между «Наблюдатель (Observer)» и «Посредник (Mediator)». Паттерн «Наблюдатель» не применим если для подписчиков важен порядок прихода сообщений, а паттерн «Посредник» как раз может это регламентировать.
Напишите как вы делаете какую-то табуретку, а то я и сам могу из книг посписывать всё это, а вот когда дело доходит до практики, почему то многие начинают сдавать позиции, и делают черти что…
почему то многие начинают сдавать позиции, и делают черти что…


Вы уверены что они знают что делают в принципе? Я вот как-то не думаю. В целом же TDD/ATDD всех спасет, ну или большинство. А так автори и так написал как он делает свои табуретки.
> А так автори и так написал как он делает свои табуретки.
Автор написал принципы, которые описаны в книгах по теории. Есть такое выражение "«ничего не знаю», покажите мне код", так вот я это и имею в виду
так вот я это и имею в виду


Обычно код чуваков, которые используют эти принципы, защищен NDA. Проблема в том что для того что бы все это продемонстрировать, нужно не простенькое приложение уровня «блог», нужно полноценное приложение со сроками разработки в человеко год. А никто просто так такое писать не будет.

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


Примеров чего? Предлагаете свои продукты в опенсурс выкладывать?
Очередная монументальная статья по эпической теме. Но вот что странно… Так много букв о том, как сделать «хорошую» архитектуру, но так и не понятно базовое: а что такое архитектура?!?
В общем, мне лично больше куда больше пользы было от коротенькой «Who Needs an Architect?» Фаулера. (Кстати, кто-нибудь видел ее перевод на русский? — студентам бы дал), чем от толстых талмудов теоретиков.
Ух! Благодарю за аттач!

Не перестаю поражаться эрудиции Фаулера!
В целом архитектура — это то что дорого и сложно поменять, а потому хорошая архитектура должна позволять нам «отменять» наши старые решения и давать возможность проще принимать новые.

То о чем пишет Фаулер — это то что отдельная позиция «архитектор» не нужна, так как это задача всей команды, формировать единое представление о системе, постоянно ее улучшать.

А то что описано в очередной монументальной статье — основные принципы и идеи, которые могут помочь провести декомпозицию системы правильно и сделать систему более гибкой и податлевой к изменениям. Очень многие не умеют делать декомпозицию или же просто не понимают как ее делать, начинают проектировать сразу самые маленькие кусочки, даже если дробить настолько нет смысла. Ну и т.д
“Самой трудной проектной задачей является нахождение наиболее адекватной декомпозиции системы на иерархически выстроенные модули, с минимизацией функций и дублирования кода” (Никлаус Вирт).

Когда мы начинали проект нам тоже казалось что «архитектор» не нужен. Это очень распотраненное мнение, что думать дорого — надо делать… как-нибудь, главное чтобы заработало. Первый вариант мы именно так и сделали. А как только вышли на рынок, то оказалось, что тут надо изменить, там слегка переделать и вот тут мы почти угадали но клиентам нужно слегка по другому, а главное стало понятно куда и как нужно продукт развивать… И если бы граммотная архитектура была заложена с самого начала, все эти доработки и измениния стоили бы нам «три копейки». Но наша программа, хоть и работала, совершенно не была предназначена для изменений — в одном месте тронешь, а в 10 начинает разваливаться.

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

Будем честными создание хорошей архитектуры — это отдельная, непростая задача, требующая усилий и квалификации. Гибкий код это, как правило, более сложный код, который использует гораздо больше абстракций и решает задачи в максимально общем виде (чем собственно и достигается то, что он подходит для очень широкого спектра различных частных случаев). Такой код сложнее писать и сложнее понимать. Он использует не наиболее простые решения, а нередко очень даже сложные но наиболее масштабируемые и адаптируемые (кто не верит посмотрите например как происходит отрисовка простейшей кнопки в JavaSwing. Вообще когда начинаешь смотреть исходники опен сорс проектов, то термин “простой” это последнее что приходит на ум).

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

Но с другой стороны, я понимаю, что для многих все написанное тут это «очередная статья ни о чем». Они правы. Тут сложная ситуация. Понятно, что код выкладывать нереально, а детский пример из трех классов ничего не объяснит. Я постараюсь в следующей статье сделать некий предельно упрощенный «макет» одной из наших программ, на котором продемонстрировать «построение табуретки».

А пока высказывание Сергея Белоусова, которое лучше всего демонстрирует то, что мне бы хотелось выразить «Самое сложное для людей — думать… У любой задачи может быть более разумное, продуманное решение, а не первое попавшееся. Люди в компании, которая занимается разработкой новых свойств продукта или платформы, должны все время думать. Задумываться о том, как то, что они делают сейчас, будет работать через много лет, как будет сопрягаться с другими вещами. Это мучительный процесс. Всегда проще не думать.»
И если бы граммотная архитектура была заложена с самого начала, все эти доработки и измениния стоили бы нам «три копейки».

У русских принято говорить: «Кабы знал, где упасть, так бы соломки подостлал». :)

Мое личное ИМХО:
Я не вижу большого смысла в попытках угадать/наворожить хорошую архитектуру. Изучение паттернов оправдано исключительно с точки зрения развития мыслительных способностей ("+", в меньшей степени, наработки какого-никакого опыта) и при производстве «типивого» софта (что тоже само по себе странно звучит). Но они (паттерны) не должны заслонять главное: правильной постановки процесса (выше где-то писали про TDD… не уловил, правда, это был сарказм или нет; я — серьезно), что является результатом постоянной рефлексии (а попросту говоря, «думать надо» — это верно). НО думать надо не абстрактно/универсально и априорно («а давайте придумаем архитектуру, которая покроет все возможные кейсы в будущем!»), а конкретно, по «отклику» («смотрите: у нас здесь проблема! давайте а) ее поправим и б) поймем, почему она возникла»). Ну и не залезать в (технические) долги — рефлексировать почаще.
В целом архитектура — это то что дорого и сложно поменять, а потому хорошая архитектура

… — это ее отсутствие. Что — увы — практически невыполнимо в современных условиях. …Что как раз и характеризует современные условия :)
Архитектура всегда есть, вы всегда можете выделить из системы компоненты, описать их взаимодействие и т.д. То что она формироваться должна не по принципу «надо все продумать» а по принципу «не знаешь какое решение тут лучше, сделай проще и так, что бы было удобно переделать», это уже другое. И именно об этом ващеет Фаулер, о чем написано куча книг еще в 90-х годах (программист прагматик, адаптивная разработка).

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

Забавно, что тут упомянут Роб Мартин. Он утверждает обратное, а именно: возможность изменений важней чем «правильность». Не корректную программу можно изменять и сделать корректной. Корректная программа может сломаться при первом же изменении.
Дядюшка Боб, конечно, далеко не всегда адекватно излагает чужие идеи, но приписывать ему такое — это не слишком? Получает, идеальная программа — пустая. Она, конечно, ничего не делает, но зато ее так легко изменить!

Не надо путать корректность программы и ее соответствие требованиям. Очевидно же: программа в любом случае должна решать поставленные задачи (соответствовать требованиям); пусть она это будет делать и не идеально (будет не «совсем корректной» или просто некорректной), но хотя бы так, чтобы ее кто-нибудь мог использовать. И уже только после этого может возникнуть желание ее изменить.
> идеальная программа — пустая
На самом деле так и есть. No code / zero code

> Она, конечно, ничего не делает, но зато ее так легко изменить!
Конечно, кажется изменять можно только то что можно проверить. Насколько профессионально с вашей точки зрения писать что-то без автоматизации тестирования?
Если «на самом деле так и есть», то дальше тут обсуждать нечего. Можете посвятить свою жизнь написанию идеального zero code и автоматизировать его тестирование …но без меня ;D

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

Побольше бы таких толковых статей!

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

Публикации

Истории