Тот факт, что некоторые типы на данный момент нельзя полноценно прописать или они требуют овер 9000 ресурсов не значит, что статик типизация не нужна. Иными словами, если вы не можете статически проверить всё, это не значит, что не надо проверять вообще ничего.
Насчёт примеров и простых случаев — в языке, на котором я пишу по работе, отсутствует Option/Maybe и почти все типы по умолчанию nullable. Сделать Optional на уровне типов — примитивщина, в разы проще тех же dependent types, но профит от неё огромен.
Собственно, мой поинт — у статик типизации есть sweet spots, где она не выливается в необходимость писать математические пруфы и позволяет реально улучшить качество и надёжность кода. Вполне возможно, со временем эта планка будет меняться и те же не отрицательные числа на уровне типов будут мейнстримом.
Накосячить можно везде. Идея типов в том, что вы «запоминаете» эту самую проверку и точно знаете, что если в функцию прилетает Int > 0, то там вообще никак не будет нуля или меньше нуля. Вам не надо смотреть все вызовы этой функции, не надо проверять самому внутри, etc.
динамические языки тем и сильны, что помимо системы типов есть другие вещи которые гарантируют корректность структур данных
Простите, я искренне не понял — а в статических языках эти «другие вещи» отсутствуют?
Проблема, которую я лично вижу в статик типизации — слабые системы типов не всегда позволяют развернуться и приходится городить очень много кода. Однако, это не делает плохой статик типизацию per se.
а далее расизм, шовинизм и евгеника: что эти нигеры себе позволяют, женщины вообще не имеют голоса, бедные и глупые должны умирать, а только богатые и здоровые имеют право на жизнь.
Я не участвую напрямую в дискуссии и только читаю, но подобное — не просто stretch, это какой-то космический прыжок в логике. Давайте уважать оппонентов и не приписывать им то, чего они не говорили явным образом. Ваши аргументы не становятся сильнее от применения slippery slope где попало.
есть среди тактических паттернов DDD те, которые на ваш взгляд точно не переусложнят и их оправданно использовать с самого начала?
Признаюсь, не так сильно вникал в DDD, поэтому все паттерны сходу не вспомню. Если считать immutable value object паттерном — то, например, он. Стараюсь в своих рабочих и домашних проектах делать immutable объекты везде, где это можно и не вызывает инфраструктурных проблем.
Если говорить о коммерческих проектах, то так же используем CQRS. (Он, строго говоря, не DDD паттерн, но для общей картины упомяну)
есть ли открытые репозитории, в которых можно посмотреть примеры реализации идей DDD на функциональных языках?
На всякий случай уточню, что конкретно я имел в виду — паттерны repository, factory, service, Aggregate Root, etc. Помимо самих паттернов, в моей основной технологии также любят их более «сложные» варианты — repository мы обязательно делаем generic потому что писать под добавления под каждую сущность это слишком, фабрики делаем абстрактными т.к. мало ли что и так далее. Всё это закидываем, разумеется, в IoC контейнер и получаем минимум 7 проектов в solution даже если пишем простейший микросервис.
для какой цели они были созданы
Как и все остальные паттерны, для упорядочивания кода, разделения ответственностей, создания какой-никакой абстракции, чтобы не читать чистый SQL там, где хотелось бы просто понять логику.
и когда, на ваш взгляд, их применение действительно оправдано?
Скажу сразу, оценить в объективных критериях это крайне сложно, поэтому в итоге всё сводится к «оправдано там, где оправдано».
На мой взгляд, эти паттерны крайне часто используют слишком рано. Я не вижу смысла в generic repository, если у вас нет такой же дженерик логики работы с сущностями. Пример, где она есть — какая-нибудь CMS, в которой пользователь может сам создавать сущности и работать с user-defined fields.
Мой основной посыл был не против этих паттернов как таковых, а скорее к тому, что грамотное DDD вполне может существовать без них. Более того, я придерживаюсь точки зрения, что DDD не обязательно должно быть в ООП парадигме. Выразите свои бизнес-правила в языке чистых функций, discriminated unions и у вас получится понятная и простая модель. Не обязательно иметь в коде классы bounded context, aggregate root, repository чтобы следовать DDD.
Одна из ишью с ddd, для меня, в том что многие люди в моей сфере (C#/Java) считают, что ddd это когда у вас интерфейсы IAggregateRoot, умные объекты и прочее. В связи с этим вокруг ddd витает дух «сложной архитектуры», о котором в статье и упоминается.
На мой взгляд, ddd не об этом. Оно о том, чтобы тесно работать с бизнесом, понимать его процессы, вникать в них. Искренне не понимаю, почему во многих проектах внедрение ddd обязательно требует невероятного усложенения архитектуры и огромной башни абстракций. Профит от минимального взаимодействия с клиентом или ЦА своего продукта (пообщаться онлайн, посмотреть на процессы в реальности, etc) в разы выше, чем все эти абстракции поверх абстракций.
Собственно, если память не изменяет, Эванс упоминал недавно, что жалеет о фокусе в своей книге и что ubiquitous language + bounded context куда важнее, чем более технические паттерны.
Почему бы мне не сидеть в комментариях? Тот факт, что стиль и направление таких статей не моё, не значит, что в комментариях не будет интересных моментов. Ну, и ещё занятно смотреть, сколько людей одобряют такого рода публикации и что пишут.
Определённо, сидеть под каждой вашей пабликацией и писать «ух как задолбало» — не очень, но я такого не замечал.
Так ведь «пипл хавает», посмотрите на их рейтинг. У каждого свои предпочтения, лично мне интереснее читать про другие вещи и я абсолютно согласен с вашей точкой зрения, но на хабре не только мы.
А если ответ сервиса поменяется (после апдейта) — у вас все посыпется
Это замечательно, и так и должно быть. Более того, если у вас есть необязательные элементы в json структуре — это тоже статически описывается на уровне типов и вы, как разработчик, явно можете наблюдать, что поле id мы ожидаем всегда и работать без него не можем, а поле birthday — опциональное.
Мне, признаюсь, глубоко непонятна идея, что динамическая типизация легче и проще. Ведь вы всё равно работаете на базе неких допущений, так почему бы их не выразить явно? Зачем мне догадываться, что будет, если вдруг придёт ответ без поля id, если я могу явно увидеть, обязательно это поле или нет? Есть чувство, что подобное отношение к статик типизации происходит от неполного понимания как её готовить и/или от работы с языками, где система типов таки да, не может выразить некоторые концепции.
tl;dr: вместо шаблонных вопросов решают вместе с кандидатом реальную задачу во всей её полноте, начиная с работы с требованиями и т.п.
Лично мне такой подход крайне импонирует и, думаю, даже провал такого собеседования будет ощущаться лучше т.к. человек сам увидит, что не справился, не разобрался, etc и как минимум получит полезный опыт. Куда полезнее заучивания всех «принципов ООП».
Справедливости ради, статистическая оценка «Х глупее У» вполне себе валид как минимум как основание для вопроса «А почему так?».
В целом, вести дискуссию в стиле «Заткнись, ты дурак» в любом случае некорректно и не конструктивно, какую бы точку зрения вы не поддерживали.
Соглашусь. Первые пара статей были интересными и relatable, но уже после половины появилось ощущение, что автор больше про «выговориться про больное». Не одобряю такое, но, видимо, я сильно в меньшинстве.
Он больше медийная фигура, как по мне. Вместе с хорошими идеями у него есть откровенные фейлы, которые стыдно читать. Для новичков не рекомендую, опытным людям не сильно и нужен.
Что характерно, многие из коллег-питонистов пришли на своих проектах к подобию строгой типизации через аннотации, сторонние решения, etc. С одной стороны, это радует, но с другой несколько обидно, что только сейчас, внезапно, приходит понимание, что javascript/python/other dynamic lang оказывается не такой удобный для крупных проектов (и не только крупных, на самом деле).
Тем забавнее вспоминать Роберта Мартина и его мысли про необходимость типизации:
You see, when a Java programmer gets used to TDD, they start asking themselves a very important question: “Why am I wasting time satisfying the type constraints of Java when my unit tests are already checking everything?” Those programmers begin to realize that they could become much more productive by switching to a dyna
mically typed language like Ruby or Python.
You don’t need static type checking if you have 100% unit test coverage. And, as we have repeatedly seen, unit test coverage close to 100% can, and is, being achieved.
Обе цитаты из «Clean Architecture: A Craftsman’s Guide to Software Structure and Design», 2017
Я не видел такого в реальных проектах. Конкретно — абсолютно ignorant логика, который было бы всё равно, какое у нас хранилище. Такое случается только если никакие фичи хранилища не используются и нам действительно всё равно. В крупных проектах, что я видел, такой роскоши нет.
Да, и я даже приводил в качестве примера ссылку на одно из лучших демонстрационных эталонных приложений (reference application)
При всём уважении к МС, это едва ли эталонное приложение, на мой взгляд.
Для более сложных случаев, когда используются усложненные сценарии создания агрегата, используется Identity Map и т.п., такой подход может привести к понижению Cohesion, и росту таких Code Smells как Shotgun Surgery или Divergent Change, что негативно отражается на экономике разработки. Хороший код всегда стремится к Low Coupling & High Cohesion. До тех пор, пока Вы в этом балансе — все ок.
Опять же, звучит очень хорошо, и в теории я со всем согласен. Изначально мой поинт был в том, что эта теория разбивается о практику, в которой репозиторий зачастую не предоставляет корректной абстрации, а является крайне глупым прокси к фреймворку доступа к базе. Соответственно, грубо говоря, недостаточно создать у себя в проекте папочки Repository, Unit of work, etc и гордо думать, что у вас хорошая архитектура. Надо понимать. какие задачи они решают и действительно ли помогут переехать на другую базу, и нужно ли это вообще. С этим у людей проблемы, и Мартин не помогает, потому как его слова — или абстрактная вода, или примеры на уровне магазина, где, конечно же, всё идеально работает.
Звучит хорошо, но я никогда такого не видел. Это в принципе характерная черта Мартина — он хорошо ставит вопросы и описывает ситуации, которых почти никогда не бывает в реальном мире.
На мой взгляд, база данных и вообще данные это крайне важное решение, поэтому откладывать их на потом не следует, если у нас не стоит выбор между «реляционная база Х» и «реляционная база У», у которых вся разница — вендор.
Опять же, я не противник отделять базу от основной логики, но есть другие способы, кроме репозиториев — простейшее разделение на commands/queries уже очень помогает.
Разве
Cast<char>не эквивалентен?Насчёт примеров и простых случаев — в языке, на котором я пишу по работе, отсутствует Option/Maybe и почти все типы по умолчанию nullable. Сделать Optional на уровне типов — примитивщина, в разы проще тех же dependent types, но профит от неё огромен.
Собственно, мой поинт — у статик типизации есть sweet spots, где она не выливается в необходимость писать математические пруфы и позволяет реально улучшить качество и надёжность кода. Вполне возможно, со временем эта планка будет меняться и те же не отрицательные числа на уровне типов будут мейнстримом.
Зависит от области, конечно, но в вебе, с которым я работаю, это не вызывает проблем. В чём именно ишью с компиляцией программы?
Приведите пример такого кода и таких проверок, плз.
Простите, я искренне не понял — а в статических языках эти «другие вещи» отсутствуют?
Проблема, которую я лично вижу в статик типизации — слабые системы типов не всегда позволяют развернуться и приходится городить очень много кода. Однако, это не делает плохой статик типизацию per se.
Я не участвую напрямую в дискуссии и только читаю, но подобное — не просто stretch, это какой-то космический прыжок в логике. Давайте уважать оппонентов и не приписывать им то, чего они не говорили явным образом. Ваши аргументы не становятся сильнее от применения slippery slope где попало.
Признаюсь, не так сильно вникал в DDD, поэтому все паттерны сходу не вспомню. Если считать immutable value object паттерном — то, например, он. Стараюсь в своих рабочих и домашних проектах делать immutable объекты везде, где это можно и не вызывает инфраструктурных проблем.
Если говорить о коммерческих проектах, то так же используем CQRS. (Он, строго говоря, не DDD паттерн, но для общей картины упомяну)
Боюсь что именно коммерческих энтерпрайз проектов в открытом доступе не видел, но есть интересная серия статей на эту тему:
fsharpforfunandprofit.com/series/designing-with-types.html
Особое внимание я обратил бы на docs.microsoft.com/en-us/dotnet/fsharp/language-reference/discriminated-unions
Очень часто возникали в работе задачи, где юнионы отлично подошли бы для моделирования нескольких возможных результатов, но т.к. я не пишу на F#, приходилось использовать enum и жить без подсказок компилятора и строгой типизации.
Как и все остальные паттерны, для упорядочивания кода, разделения ответственностей, создания какой-никакой абстракции, чтобы не читать чистый SQL там, где хотелось бы просто понять логику.
Скажу сразу, оценить в объективных критериях это крайне сложно, поэтому в итоге всё сводится к «оправдано там, где оправдано».
На мой взгляд, эти паттерны крайне часто используют слишком рано. Я не вижу смысла в generic repository, если у вас нет такой же дженерик логики работы с сущностями. Пример, где она есть — какая-нибудь CMS, в которой пользователь может сам создавать сущности и работать с user-defined fields.
Мой основной посыл был не против этих паттернов как таковых, а скорее к тому, что грамотное DDD вполне может существовать без них. Более того, я придерживаюсь точки зрения, что DDD не обязательно должно быть в ООП парадигме. Выразите свои бизнес-правила в языке чистых функций, discriminated unions и у вас получится понятная и простая модель. Не обязательно иметь в коде классы bounded context, aggregate root, repository чтобы следовать DDD.
На мой взгляд, ddd не об этом. Оно о том, чтобы тесно работать с бизнесом, понимать его процессы, вникать в них. Искренне не понимаю, почему во многих проектах внедрение ddd обязательно требует невероятного усложенения архитектуры и огромной башни абстракций. Профит от минимального взаимодействия с клиентом или ЦА своего продукта (пообщаться онлайн, посмотреть на процессы в реальности, etc) в разы выше, чем все эти абстракции поверх абстракций.
Собственно, если память не изменяет, Эванс упоминал недавно, что жалеет о фокусе в своей книге и что ubiquitous language + bounded context куда важнее, чем более технические паттерны.
Определённо, сидеть под каждой вашей пабликацией и писать «ух как задолбало» — не очень, но я такого не замечал.
Так ведь «пипл хавает», посмотрите на их рейтинг. У каждого свои предпочтения, лично мне интереснее читать про другие вещи и я абсолютно согласен с вашей точкой зрения, но на хабре не только мы.
Это замечательно, и так и должно быть. Более того, если у вас есть необязательные элементы в json структуре — это тоже статически описывается на уровне типов и вы, как разработчик, явно можете наблюдать, что поле id мы ожидаем всегда и работать без него не можем, а поле birthday — опциональное.
Мне, признаюсь, глубоко непонятна идея, что динамическая типизация легче и проще. Ведь вы всё равно работаете на базе неких допущений, так почему бы их не выразить явно? Зачем мне догадываться, что будет, если вдруг придёт ответ без поля id, если я могу явно увидеть, обязательно это поле или нет? Есть чувство, что подобное отношение к статик типизации происходит от неполного понимания как её готовить и/или от работы с языками, где система типов таки да, не может выразить некоторые концепции.
blog.usejournal.com/rethinking-how-we-interview-in-microsofts-developer-division-8f404cfd075a
tl;dr: вместо шаблонных вопросов решают вместе с кандидатом реальную задачу во всей её полноте, начиная с работы с требованиями и т.п.
Лично мне такой подход крайне импонирует и, думаю, даже провал такого собеседования будет ощущаться лучше т.к. человек сам увидит, что не справился, не разобрался, etc и как минимум получит полезный опыт. Куда полезнее заучивания всех «принципов ООП».
В целом, вести дискуссию в стиле «Заткнись, ты дурак» в любом случае некорректно и не конструктивно, какую бы точку зрения вы не поддерживали.
Он больше медийная фигура, как по мне. Вместе с хорошими идеями у него есть откровенные фейлы, которые стыдно читать. Для новичков не рекомендую, опытным людям не сильно и нужен.
Тем забавнее вспоминать Роберта Мартина и его мысли про необходимость типизации:
2016 год, если что.
Я не видел такого в реальных проектах. Конкретно — абсолютно ignorant логика, который было бы всё равно, какое у нас хранилище. Такое случается только если никакие фичи хранилища не используются и нам действительно всё равно. В крупных проектах, что я видел, такой роскоши нет.
При всём уважении к МС, это едва ли эталонное приложение, на мой взгляд.
Опять же, звучит очень хорошо, и в теории я со всем согласен. Изначально мой поинт был в том, что эта теория разбивается о практику, в которой репозиторий зачастую не предоставляет корректной абстрации, а является крайне глупым прокси к фреймворку доступа к базе. Соответственно, грубо говоря, недостаточно создать у себя в проекте папочки Repository, Unit of work, etc и гордо думать, что у вас хорошая архитектура. Надо понимать. какие задачи они решают и действительно ли помогут переехать на другую базу, и нужно ли это вообще. С этим у людей проблемы, и Мартин не помогает, потому как его слова — или абстрактная вода, или примеры на уровне магазина, где, конечно же, всё идеально работает.
На мой взгляд, база данных и вообще данные это крайне важное решение, поэтому откладывать их на потом не следует, если у нас не стоит выбор между «реляционная база Х» и «реляционная база У», у которых вся разница — вендор.
Опять же, я не противник отделять базу от основной логики, но есть другие способы, кроме репозиториев — простейшее разделение на commands/queries уже очень помогает.