Башня Байткода
69 subscribers
26 photos
2 files
27 links
Авторские заметки об архитектуре ПО на основе реальной практики.

github: https://github.com/PHPTCloud
Download Telegram
#arch #ddd
Проектирование по модели предметной области становится возможным только в том случае, если четко отделен уровень предметной области. В многоуровневой архитектуре таким уровнем является Доменный слой (Domain Layer), который мы ранее рассматривали в Гексагональной архитектуре.

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

Изолирование доменного слоя от кода интерфейса пользователя, прикладных операций и инфраструктуры позволяет модели развиться до достаточно сложной и в то же время достаточно понятной, чтобы заключить в себе существенные знания о предмете и эффективно их применить.
👍4🔥3
#arch #ddd
Модель, выраженная в программе
Чтобы суметь найти компромиссы в программной реализации и при этом не по­терять преимуществ проектирования по модели, связь между моделью и реализацией необходимо прорабатывать на уровне деталей.
В эти детали входят: ассоциации, сущности, объекты значений, службы, модули.

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

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

Существует как минимум три способа сделать ассоциации более удобными и управляемыми:

1️⃣Свести отношения к однонаправленным, прослеживаемым в одном направлении.

2️⃣Добавить квалификаторы, тем самым явно ограничивая ассоциацию. Например, от "один ко многим" до "один к одному"

3️⃣Устранить несущественные ассоциации. Например, избавиться от транзитивных зависимостей.

❗️Важно ограничить взаимосвязи до минимума. Двунаправленные ассоциации означа­ют, что два объекта можно понять только совместно, как одно целое. Если техническое задание непосредственно не требует двунаправленных отношений, то сведение их к однонаправленным снижает взаимозависимость и упрощает струк­туру программы (соблюдается принцип low coupling).
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥3🤯1
#arch #ddd
Сущности (Entities)

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

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

Для сущностей (в отличие от других объектов) определение через атрибуты не является главным. Иногда сущности приходится ставить в соответствие другому объекту, хотя их атрибуты отличаются. Или же сущность требуется отличать от другого объекта, хотя их атрибуты могут быть одинаковыми.
Сущность - это все то, что сохраняет свое индивидуальное существование и отличие на протяжении срока "жизни", независимо от атрибутов.

При реализации программы необходимо придерживаться следующих правил:
❗️Следует ограничить определение объекта-сущности наиболее неотъемлемыми его характеристиками, т.е. теми, которые однозначно выделяют его среди других и обычно используются для его поиска и сравнения.
❗️Задавайте только те рабочие функции, которые существенны для создания понятия об объекте, и только те атрибуты, которых требуют эти функции.
❗️Все атрибуты и функции, которые выходят за эти рамки, старайтесь выносить в другие объекты, ассоциированные с главной сущностью. Некоторые из них тоже будут сущностями, а некоторые - объектами-значениями (о них мы поговорим ниже).
❗️Для каждого объекта-сущности должен быть задан способ сопоставления его с другим объектом - такой, который бы позволял различать их даже в случае совпадения описательных атрибутов.
❗️Идентифицирующий атрибут должен гарантировано оставаться уникальным в пределах системы, независимо от способа ее определения - в распределенной системе и в архиве.

Кроме индивидуальности и непрерывно­сти существования, для сущностей часто характерно то, что они выполняют свои функ­ции, координируя операции объектов, которые им принадлежат.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥2🤯1
#arch #ddd #exp
Объект-значение (Value Object)

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

Правила проектирования объектов-значений:
❗️Нужно различать, когда и что использовать (сущность, объект-значения), чтобы специальные приемы работы с объектами использовались только тогда, когда нужно.
❗️Если элемент модели полностью определяется своими атрибутами, то его следует считать объектом-значением.
❗️Сделаи‌те так, чтобы он отражал смысл заложенных в него атрибутов и придаи‌те ему соответствующую функциональность.
❗️Считаи‌те такои‌ объект неизменяющимся. Изменение значения (value) может привести к повреждению объекта-владельца путем искажения его инвариантов.
❗️Не даваи‌те ему индивидуальности, вообще избегаи‌те любых сложностеи‌, неизбежных при программном управлении сущностями.

* В своей практике я сталкивался с объектами-значениями в системе. Но лично мне кажется, что это бомба замедленного действия 🤌
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥3🤔1
#arch #ddd
Службы (Service)

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

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

❗️Инфраструктурный слой - технические службы без доступа к бизнес логике.
❗️Операционный слой - службы, которые “взаимодействуют” с пользователем.
❗️Доменный слой - службы, охватывающие предметную модель без доступа к функционалу, доступному пользователю напрямую.

Хорошая Служба обладает тремя свойствами:
1️⃣Объект службы нельзя отнести ни к объекту-сущности, ни к объекту значения.

2️⃣Определена собственным интерфейсом внутри доменного слоя.

3️⃣Операция не имеет собственного состояния.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥2🤔1
#arch #ddd
Модули (Module)

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

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

Как и все остальное в искусстве DDD, Модули являются механизмом коммуникации. <...> Если вы помещаете несколько классов в один Модуль, вы тем самым гово­рите вашему преемнику, которому предстоит изучать эту архитектуру: думай о них вместе, как о целом. Если ваша модель рассказывает историю, то Модули - это ее главы.

Эрик Эванс


При проектировании Модулей придерживайтесь следующих правил:

❗️Добивайтесь низкой зависимости модулей друг от друга, чтобы понятия в разных модулях можно было анализировать и воспринимать независимо друг от друга.
❗️Дорабатывайте модель до тех пор, пока в ней не возникнут естественные границы в соответствии с высокоуров­невыми концепциями предметной области, а соответствующий код не разделится соответствующим образом.
❗️Дайте модулям такие имена, которые войдут в Единый язык. Как сами Модули, так и их имена должны отражать знание и понимание предметной области.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥2
#arch #ddd #exp
Ловушки инфраструктуры

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

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

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

😒 И снова low coupling + high cohesion
Иногда для формирования пакетов, способных отразить модель, достаточно соблюдать правила высокой внутренней связности и низкой внешней зависимости пакетов (low coupling and high cohesion).
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥4🤔1
#arch #ddd
Управление объектами системы

Спроектировать и внедрить “правильные” объекты архитектуры недостаточно - объектами необходимо управлять, и здесь могут возникнуть трудности, такие как поддержание целостности объекта на протяжении жизни или излишняя сложность в управлении циклом существования объекта. Решать эти проблемы DDD предлагает с помощью агрегатов, фабрик и хранилищ.

В чем ценность данных шаблонов?

Каждый объект имеет свой цикл существования. Объект “рождается“, затем проходит ряд сменяющихся состояний, а потом “умирает“ - либо удаляется, либо помещается в архив. Моделирование Агрегатов с добавлением в программу Фабрик и Хранилищ дает нам возможность манипулировать объектами систематически, в естественных смысловых границах, на протяжении всего цикла их существования.

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

❗️Фабрики используются для создания и восстановления сложных объектов и Агрегатов с сохранением инкапсуляции их внутренней структуры.

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

Хотя Хранилища и Фабрики непосредственно не происходят из предметной области, они играют важную смысловую роль в ее архитектуре, помогая удобно обращаться с объектами при Проектировании по модели.

Каждый из паттернов заслуживает детального рассмотрения.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥2
#arch #ddd
Агрегаты (Aggregate)

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

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

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

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

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

❗️ Группируйте Сущности и Объекты-значения в Агрегаты и определяйте границы каждого из них.

❗️ Корневой объект. Выберите один объект-сущность и сделайте его корневым. Осуществляйте все обращения к объектам в границах Агрегата только через его корневой объект. Разрешайте внешним объектам хранить ссылки только на корневой объект. Корневой объект может передать копию объекта-значения другому объекту, и что с ней потом случится не играет роли, поскольку это не более чем значение, и оно не имеет никаких связей с Агрегатом. Корневой объект имеет глобальную идентичность и несет полную ответственность за проверку инвариантов.

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

❗️ Как только вносится изменение в любой объект внутри границ Агрегата, следует сразу удовлетворить все инварианты этого Агрегата.

❗️ Операция удаления должна одновременно ликвидировать все, что находится в границах Агрегата.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍4🤔1
#exp #ddd #arch
Агрегаты на практике

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

Приведу пример из финансовой области. Итак, предположим наша команда занимается выдачей займов. К нам приходит Иван Иваныч, просит 100 тысяч русских долларов. Указывает все свои данные в форме на сайте, отправляет заявку на выдачу займа. Мы показываем ему несколько документов на подпись, Иваныч как-то все подписывает, переводим заявку в статус "Ожидает аудит". Проводим проверку его заявки, если все ок, то Иваныч получает деньги и начинает "жить" у нас в системе.

Пример инвариантов Агрегатов

Инвариант первый. Оформление заявки на займ.

Продолжим пример. Иваныч заполнил форму и отправил ее. В этот момент мы получили из БД инфу о пользователе (User) и создали запись о новой заявке на займ (Order) в статусе "оформление заявки" + отправили задачу на формирование документов для подписания. Чтобы не создавать все объекты по отдельности, можно реализовать агрегат (LoanAggregate) и службу для него (LoanService). В LoanService добавим метод createNewOrder(array attributes): LoanAggrate, в аргументе которого будет минимальный набор данных для создания агрегата. Сам агрегат будет обычным объектом и будет содержать инфу о User-сущности и корневой сущности Order. Чтобы сохранить агрегат в первом инварианте сделаем метод LoanService::toAwaitingDocuments, который проверит корректность данных и зафиксирует данные в БД.


Инвариант второй. Подписание документов.

Когда документы сгенерированы и мы получили коллекцию документов в коде, привязываем их к агрегату. Для сборки агрегата в актуальном инварианте используем новый метод LoanService::getLoan(userId): LoanAggregate.

Чтобы изменить инвариант агрегата на второй, в сам агрегат добавляем новый метод addDocument(Document document), а в LoanService добавляем метод toDocumentsSigning, который проверит агрегат и зафиксирует новый инвариант (подписание документов).

Инвариант третий. Ожидание аудита.

Когда LoanAggregate будет переведен во второй инвариант и Иваныч как-то подпишет документы, мы переведем агрегат в следующий инвариант с помощью нового метода LoanService::toAwaitingAudit(). Кстати, если вы храните подписи документов в объектах-сущностях, то для агрегата можно сделать новый метод addSignature(Signature signature) и дополнить сборку агрегата в Фабрике (о фабриках позже).

Надеюсь, логика изменения инвариантов агрегата стала более понятной. Количество инвариантов агрегата может быть разным, но очень важно помнить о соблюдении границ агрегата. Из опыта могу посоветовать не делать большие агрегаты и не использовать агрегаты более чем в 1-2 бизнес-процессах. В идеале использовать один агрегат для одного сложного бизнес-процесса, т.к. частные случаи в процессе могут зааффектить производительность. Даже если вам кажется, что можно переиспользовать агрегат в другом бизнес-процессе, - вам кажется 😏
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥2🤯1
#arch #ddd
Фабрики (Factories)

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

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

Фабрика (Factory) - элемент программы, обязанность которого - создавать объекты.
Несмотря на то, что Фабрики могут не выполнять никаких функций в Модели предметной области, они являются элементом ее архитектуры.

Для чего нужны Фабрики:

❗️ Позволяют делегировать создание экземпляров сложных объектов и Агрегатов, облегчая их восприятие разработчиком;

❗️ Инкапсулируют внутреннюю структуру от посторонних глаз;

❗️ С помощью интерфейса дают клиенту абстракт­ное представление создаваемого объекта, не требуя ссылаться на конкретные классы при сборке.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🤔2🔥1
🧠 Как увеличить стоимость себя, как специалиста, минимум вдвое?

Я делю специалистов на два класса: обычный и класса А.

Например, meddle/senior (и т.д.) ux/ui дизайнер и meddle/senior ux/ui дизайнер класса А.

Первый, мастер в дизайне/коде/тестировании.
Второй, тоже мастер в этом же, но у него есть один изюм.

🎯 Второй понимает ПОЧЕМУ он делает дизайн/код/тестирует.


Как его работодатель будет на этом зарабатывать, как клиенты работодателя будут на этом зарабатывать.

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

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

Это как встать в точку зрения бизнеса с определенной стороны. Собственники её не видят. Это твоя выигрышная позиция. Можно договариваться.

Взять на себя роль держателя точки зрения и попросить за это справедливую плату/долю.

5АМ | #мотивация
🔥3👍2✍1
#testing
Mutation Score Indicator (MSI)

Mutation Score Indicator (MSI) — это мощный метод оценки качества тестов, где в код вносятся искусственные ошибки (мутации), чтобы проверить, насколько хорошо тесты их обнаруживают.

Пример мутаций:
- Замена операторов (+ на -)
- Изменение условий (if x > 0 → if x >= 0)
- Удаление строк кода

После внесения изменений запускаются тесты. Результаты делятся на:

✔️ Убитые мутации — тесты упали (хороший результат)
❌ Выжившие мутации — тесты прошли (проблема в покрытии)

MSI рассчитывается по формуле:
MSI = (Убитые мутации / Всего мутаций) × 100%

Например, при 85 убитых мутациях из 100:
MSI = (85 / 100) × 100% = 85%

Интерпретация результатов:
🥇 90-100% — отличное покрытие
🥈 70-89% — приемлемый уровень
🚫 <70% — требуется доработка тестов

Преимущества подхода:
- Показывает реальную эффективность тестов
- Выявляет слабые места в тест-кейсах

Недостатки:
- Требует значительных ресурсов
- Возможны ложные срабатывания
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1
#testing
Infection — мутационное тестирование для PHP

Infection — это крутой инструмент, который:

- Создаёт "мутации" (искусственные баги) в коде
- Проверяет, падают ли тесты на этих изменениях
- Даёт MSI-метрику — % "убитых" мутаций

Как это помогает?
- Находит "спящие" баги, которые тесты пропускают
- Показывает реальную эффективность тестов (не путать с code coverage)
- Особенно полезно для критически важного кода

Пример результата:
Mutation Score: 85%
✔️ 34 mutations killed
❌ 6 mutations survived

https://github.com/infection/infection
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
Forwarded from PHP Fart Time (Pavel Buchnev)
Из-за сбоя у облачного провайдера, у нас в кластере k8s автоскейлинг сошел с ума и вместо максимально 5 нод нам накинулось почти 100 нод в кластер. За пару дней сожрались все бабки на счете)
Вывод: настривайте мониторинг везде и всегда. Без него вам жопа!
Я, кстати, уже не первый раз из-за мониторинга попадаю в такие ситуации.
#management

Чайка-стайл

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

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

https://habr.com/ru/articles/953304/
👍3
#arch #standards #essa

Опубликовал спецификацию ESSA - стандарт, который фиксирует архитектурные ограничители.

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

💬 Для процесса код-ревью есть функция цитирования.

⚡️ Доступна markdown-версия: хочу довести ее до ума, чтобы ИИ смогла писать бэк по стандарту.

Ссылка на спецификацию: https://essa-spec.ru
Документация: https://essa-spec.ru/docs

Буду благодарен обратной связи и предложениям по улучшению 💔
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4