Search
Write a publication
Pull to refresh

Comments 13

А мы можем в рамках интерфейса указать, что какие-то значения мы поглощаем, а какими-то только пользуемся? Например, если мы из UnregisteredUser делаем RegisteredUser, то как можно сказать, что после передачи объекта типа Unregistereduser в конструктор RegisteredUser::register, оригинальным значением больше нельзя использовать?

Мне кажется, что это как раз то, чем занимается borrow checker в Rust.

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

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

Наверное это может выглядеть аналогичено тому как реализуется Lazy Load. Как вариант, в интерфейсе это может выглядеть так:


public RegisteredUser Register(IWouldAbsorbedHere<UnregisteredUser> user)

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

Только непонятно, почему автор использует термин "архитектура". Раз мы оперируем классами, то речь идёт об иммутабельном дизайне. Архитектура лежит выше и даже не знает, что там внизу - ООП, ФП или процедурщина.

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

А вот теперь я с Вами не соглашусь :)

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

К слову, ещё один вариант архитектуры с разделением на мутабельные и иммутабельные части – CQRS, только там они не оборачивают друг друга, а существуют параллельно.

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

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

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

Примеры тоже все про разделение ответственности по классам, а значит -- про дизайн.

CQRS я просто вспомнил как ещё один пример архитектуры с разделением мутабельности/иммутабельности, к теме статьи это никак не относится.

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

Думаю, автору понравится MediatR и введение в F#, включая Railway Oriented Programming.

Sign up to leave a comment.

Articles