Чистая архитектура

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

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

Предисловие

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

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

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

Определение архитектуры

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

— Гради Буч
Определение хорошей архитектуры

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

О дороговизне хорошей архитектуре

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

— Брайан Фут и Джозеф Йодер

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

Определение архитектуры

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

— Ральф Джонсон

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

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

К цели ведёт много путей.

Вспоминается "Задачи можно решать по-разному".

Он [третий, чистый путь - два других чуть выше по тексту]:

  • учитывает природную гибкость программного обеспечения и стремится сохранить её как основное свойство системы.

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

  • играет больше на наших сильных сторонах, чем на слабостях.

Определение хорошей архитектуры

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

Определение архитектуры

Архитектура - это гипотеза, которую требуется доказать реализацией и оценкой.

— Том Гилб

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

Поспешай не торопясь.

— Роберт С. Мартин

Об этом автор упоминает ещё на стр. 31 в строках "чем больше спешишь, тем меньше успеваешь."

Получайте удовольствие от путешествия.

— Кевлин Хенни

Вступление

  1. Все архитектуры подчиняются одним и тем же правилам!

  2. Правила создания архитектур не зависят от любых других переменных.

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

... важное сходство современного ПО и прошлого ПО: и то и другое сделано из того же материала. Оно состоит из инструкций if, инструкций присваивания и циклов while.

... программный код до сих пор состоит из последовательностей операций, условных инструкций и итераций, как и в 1950-х и 1960-х годах.

... основные строительные блоки компьютерных программ остались прежними.

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

[Эти] Правила определяют последовательность и порядок компоновки программ из строительных блоков.

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

Именно указанным в цитате выше правилам, не стареющим и не изменяющимся, посвящена эта книга.

Часть I

Введение

... заставить что-то работать - один раз - не очень сложно.

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

  • вам не требуются толпы программистов для поддержки его работоспособности;

  • вам не нужна объёмная документация с требованиями и гигантские баг-трекеры;

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

  • Правильный программный код не требует больших трудозатрат на своё создание и сопровождение.

  • Изменения вносятся легко и быстро.

  • Ошибки немногочислены.

  • Трудозатраты минимальны, а функциональность и гибкость - максимальны.

Определение хорошей архитектуры

Хорошая архитектура оказывает на систему, проект и коллектив разработчиков невероятный эффект.

Выше немного изменил исходный текст автора.

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

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

1. Что такое дизайн и архитектура?

Прежде всего, я утверждаю, что между этими понятиями [дизайн и архитектура] нет никакой разницы. Вообще никакой.

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

Но такое разделение бессмысленно, когда речь идёт о том, что делает настоящий архитектор.

Определение архитектуры.

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

То же относится к архитектуре ПО. Низкоуровневые детали и высокоуровневая структура являются частями одного целого. Они образуют сплошное полотно, определяющее форму системы. Одно без другого невозможно; нет никакой чёткой линии, которая разделяла бы их.

Есть просто совокупность решений разного уровня детализации.

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

Цель?

Цель архитектуры ПО

Цель архитектуры ПО - уменьшить человеческие трудозатраты на создание и сопровождение системы.

— Роберт С. Мартин
Определение хорошей архитектуры

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

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

Таким образом, хорошая архитектура системы - это та архитектура, при которой трудозатраты на:

  • создание этой системы невелики;

  • её сопровождение остаются небольшими в течение всего срока эксплуатации.

Причины неприятностей

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

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

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

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

Что не так?

Притча [басня Эзопа о Зайце и Черепахе] подчеркивает глупость самонадеянности.

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

... разработчики никогда не переключают режим работы [см. причину на стр. 31]. Они не могут вернуться и навести порядок, потому что должны реализовать следующую новую функцию, а потом ещё одну, и ещё, и ещё. В результате беспорядок нарастает, а продуктивность стремится к своему пределу около нуля.

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

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

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

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

"создание беспорядка …​ медленнее" - здесь можно подумать, что переводчик ошибся и что здесь вместо "медленнее" должно быть "быстрее" - но это не так. Ниже автор показывает, что в перспективе соблюдение порядка (чистоты) приведёт к более высокой скорости разработки.

... они [те, кто не поддался обману самонадеянности Зайца] знают простую истину разработки ПО: Поспешай не торопясь.

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

О перепроектировании (переделке с нуля)

Та же самонадеянность [Зайца], которая прежде уже привела к беспорядку, теперь снова говорит им [разработчикам], что они смогут построить лучшую систему, если только вновь вступят в гонку [начав всё с самого начала и перепроектировав всю систему целиком].Однако в действительности не всё так радужно: Самонадеянность, управляющая перепроектированием, приведёт к тому же беспорядку, что и прежде.

Заключение

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

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

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

Определение хорошей архитектуры

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

2. История о двух ценностях

О двух ценностях программных систем

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

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

Поведение

О назначении программистов

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

О жестокой ошибке программистов

Многие программисты полагают, что этим [3] их работа ограничивается. Они уверены, что их задача - заставлять компьютеры соответствовать требованиям и исправлять ошибки. Они жестоко ошибаются.

Архитектура

Об идее программного обеспечения

Идея ПО состоит в том, чтобы дать простую возможность изменять поведение компьютеров.

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

Для достижения этой цели [способность дать простую возможность изменять поведение компьютеров] ПО должно быть податливым - т.е. должна быть возможность легко изменить его.

Сложность в таких случаях [когда необходимо изменить что-то в ПО по требованию заинтересованных сторон] должна быть пропорциональна лишь масштабу изменения, но никак не его [изменения] форме <1>.

Именно: <2>

  • эта разница между масштабом и формой часто является причиной роста стоимости разработки ПО.

  • по этой причине стоимость растет пропорционально объему требуемых изменений.

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

С точки зрения разработчиков, заинтересованные стороны формируют поток фрагментов, которые они должны встраивать в мозаику со все возрастающей сложностью. Каждый новый запрос [от заинтересованных сторон на внесение изменений] сложнее предыдущего, потому что форма системы не соответствует форме запроса.

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

1 Надо осмыслить TBD
2 Надо осмыслить TBD
Определение хорошей архитектуры.

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

Наибольшая ценность

О том, что важнее

Я могу доказать ошибочность этого взгляда [что важнее правилььная работа, а не простота ее изменения] простым логическим инструментом исследования экстремумов.

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

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

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

О разумных пределах стоимости изменений

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

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

Матрица Эйзенхауэра

У меня есть два вида дел, срочные и важные. Срочные дела, как правило, не самые важные, а важные - не самые срочные. [4]

— Дуайт Дэвид Эйзенхауэр

Первая ценность программного обеспечения - поведение - это нечто срочное, но не всегда важное. Вторая ценность - архитектура - нечто важное, но не всегда срочное.

... имеются также задачи важные и срочные одновременно и задачи не важные и не срочные.

Все четыре вида задач можно расставить по приоритетам.

  1. Срочные и важные

  2. Несрочные и важные

  3. Срочные и не важные

  4. Не срочные и не важные.

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

Руководители и разработчики часто допускают ошибку, поднимая пункт 3 ("срочные и не важные") до уровня пункта 1. Иными словами, они неправильно отделяют срочные и не важные дела от задач, которые по-настоящему являются срочными и важными.

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

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

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

Как я понял, вывод "…​ именно для её решения они и были наняты" сделан автором на базе следующего умозаключения:

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

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

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

Смотри чуть ниже о борьбе разработчиков 2 - там автор говорит о том, что защита своего интереса в ПО - "одна из причин, почему вас [разработчиков] наняли". Т.е. защита интересов в ПО также ведёт опосредованно к тому, чтобы обеспечивались хорошие дизайн и архитектура.

О борьбе разработчиков 1

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

... также как команда управленцев, команда маркетинга, команда продаж и команда эксплуатации. Это всегда борьба.

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

О борьбе разработчиков 2

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

О задачах архитектора

Важность этой задачи [защищать свой интерес в ПО] удваивается, если вы выступаете в роли архитектора ПО.

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

Архитекторы создают архитектуру, помогающую быстрее и проще:

  • создавать эти особенности и функции,

  • изменять их и дополнять.

Выше автор явно не говорит, но это следует из контекста - к задаче архитектора также относится и защита своих интересов в ПО.

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

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

Часть II. Начальные основы: парадигмы программирования

Алан Тьюринг первым понял, что программы - это всего лишь данные.

С тех пор [с 1945 года, как я понял] в программированиии произошло несколько революций. Одна из самых известных - революция языков.

Другая, ещё более важная, как мне кажется, революция [в программировании] произошла в парадигмах программирования. Парадигма - это способ программирования, не зависящий от конкретного языка.

Парадигма определяет:

  • какие структуры использовать

  • и когда их использовать.

До настоящего времени было придумано три такие парадигмы.

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

TBD Сослаться на эти причины.

3. Обзор парадигм

Структурное программирование

Главное о структурном программировании

Структурное программирование накладывает ограничение на прямую передачу управления [через посредство инструкций перехода goto].

Парадигму структурного программирования предложил Эдсгер Вибе Дейкстра в 1968 году. Он показал вред goto и предложил заменить goto более понятными коснтрукциями if/then/else и do/while/until.

Объектно-ориентированное программирование

Главное об Объектно-ориентированном программировании

В результате [перемещения кадра стека вызова функции в динамическую память (кучу), приводящую к тому, что локальные переменные, объявленные внутри функции, могут сохраняться после выхода из неё] функция превращалась в конструктор класса, локальные переменные - в переменные экземпляра, а вложенные функции - в методы.

Это привело к открытию полиморфизма через строгое использование указателей на функции.

Подводя итог [к вышесказанному], можно сказать, что:

Объектно-ориентированное программирование накладывает ограничение на косвенную передачу управления.

Парадигма ООП появилась двумя годами ранее, в 1966 году. Предложена Оле-Йоханом Далем и Кристеном Нюгором.

Функциональное программирование

Главное о функциональном программировании

TBD Продолжить отсюда


1. Ещё одна система координат - время, деньги, трудозатраты, помогающая нам различать большое и малое и отделять относящееся к архитектуре от всего остального
2. Когда их продуктивность начинает приближаться к нижнему пределу - к нулю - см. график на рис. 1.4 "Изменение продуктивности с выпуском новых версий"
3. Разработка функциональной спецификации или документ с требованиями; написание кода для удовлетворения этим требованиям; исправление проблем при нарушении компьютерами/программными системами требований.
4. Из речи, произнесенной в Северо-Западном университете в 1954 году.