• Межмодульная коммуникация в расширяемых приложениях?

    @ddd329
    Нее, интеграция посредством СООБЩЕНИЙ штука не такая простая, она в основном требуется в больших корпоративных приложениях, когда существует множество приложений, между которыми необходимо настроить взаимодействие.
    В Вашем случае все намного проще для того, чтобы разбить монолит на отдельные модули. Есть такой паттерн как "Plugin", который описан в книге Фаулера по шаблонам корпоративных приложений.
    Я бы сделал так: создал отдельный проект, где приведены контракты модулей, т.е. программные интерфейсы. Ну а далее в других проектах идет реализация этих контрактов/интерфейсов...
    Ответ написан
    Комментировать
  • Проектирование структуры приложений для начинающего?

    @ddd329
    Могу дать такие советы, как вижу это я.

    Разделить приложение на три уровня:
    1) Presentation - уровень представления, при помощи которого пользователь взаимодействует с приложением;
    2) Business Logic - слой бизнес-логики;
    3) Persistence - слой где хранятся данные, но обычно это реляционная БД.

    Если это настольное приложение, то слой Presentation разбей на три компонента согласно паттерну MVP (Model-View-Presenter), если это классическое веб-приложение, то паттерну MVC (Model-View-Controller).

    Слой бизнес-логики реализуй согласно паттерну Transaction Script, ну либо паттерну Модель предметной области, где для начала будет анемичная модель (anemic model), которая полностью совпадает со схемой БД, а логику храни в сервисах. Далее когда наберешься скиллов, то можешь пробовать из анемичной модели предметной области сделать богатую (rich model), для этого можешь обратить внимание на методологию DDD (Domain-Driven-Design).

    Ну и слой хранения, тут пока тупо через средства ORM...

    Ну примерно так, ничего нового и волшебного тут нету.
    Ответ написан
    Комментировать
  • Как спроектировать проверку?

    @ddd329
    Привет! Ну если вопрос касается проектирования, то тут сразу бросается в глаза понятие Service. В предметной области его желательно не использовать, т.к. данный термин очень перегруженный и имеет много понятий в программировании. Я видел в одном проекте его заменили на Product, но ладно не суть...
    Паттерн "Спецификация" я думаю тут не особо уместен. Можно сделать так, что каждый Сотрудник содержит в себе поле со списком Документов, и для того чтобы выяснить может ли сотрудник оказывать услугу, то можно примерно так:
    if (employee.СanProvideService(service)) ...
    Ответ написан
    Комментировать
  • Как собрать мысли в кучу при большом рефакторинге?

    @ddd329
    Тут могу посоветовать пока только Фаулера и его книгу про рефакторинг ссылка.
    Есть еще одна книга по работе с унаследованным кодом ссылка, но перевод ее настолько ужасен, что как бы и не советую, но те кто читал ее в оригинале, говорят что очень хороша!
    Я считаю, что никакими советами и статьями здесь не обойдешься, надо читать.
    Читай, иначе обречен на неудачу!
    Ответ написан
    Комментировать
  • C чего начинать проектирование ПО: со структуры БД или бизнес-логики?

    @ddd329
    На этот вопрос я бы ответил так: начинать проектирование надо не со схемы базы данных, и не с бизнес-логики. Конечно, я и сам обычно начинаю создание именно с проектирования схемы БД, но в целом тогда, когда предметная область мне знакома и ясна.
    Вы создаете приложение, а значит вам необходимо знать и понимать кто будет использовать вашу систему и, главное - какие проблемы будет решать ваш программный продукт. И это очень важно!
    Например: вам необходимо автоматизировать деятельность платной библиотеки. Использовать ее будут администратор, сотрудник библиотеки и читатель.
    Далее, нам необходимо решить какие сценарии использования (так называемые use case) будет реализовано в нашем приложении, т.е. как эти люди (actor) будут использовать нашу систему.
    Администратор - управление сотрудниками библиотеки, учет книг;
    Сотрудник библиотеки - выдача книг, возврат книг, продажа абонементов;
    Читатель - резервирование книг, продление книг, оплата книг и т.д.

    А вот когда мы понимаем, кто и как будет использовать наш программный продукт, тогда мы уже можем приступать к реализации бизнес-слоя. Причем не обязательно, что вам необходимо строить полноценную модель предметной области, вы можете ее не строить, удобный шаблон реализации бизнес-слоя - это сценарий транзакции (Transaction Script).
    Если все же решили делать модель предметной области, то тут необходимо решить какая она будет, анемичная (anemic ) или богатая (rich). В первом случае вся логика сосредоточена в сервисах бизнес-слоя, а сами сущности предметной области простые контейнеры данных, которые обычно один в один совпадают со схемой базы данных. Во втором случае, основная логика бизнес-поведения сосредоточена в классах бизнес-сущностей.
    Ну как-то так...
    Ответ написан
    Комментировать
  • Как правильно обрабатывать входящие данные?

    @ddd329
    Когда твои данные дойдут до ApplicationLayer, то служба этого уровня, должна достать агрегат из репозитория, и над этим агрегатом произвести действия на основе входящих данных. Например, если отредактировали фамилию пользователя, то:
    1. var user = userRepository.GetById(777);
    2. user.LastName = inputData.LastName;
    3. userRepository.Save(user);

    В таком духе...
    Ответ написан
    Комментировать
  • Как загружать вложенные сущности в ddd?

    @ddd329
    У меня есть сущности и репозитории к ним.

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

    Загружать вложенные сущности нельзя, потому как:
    1. Сущность не может обращаться к репозиторию, она может иметь только ссылки на другие сущности и на объекты-значения;
    2. Грузить надо сразу целый граф безо всякой отложенной загрузки.
    Проблема такой загрузки в том что в случае создания списка сущностей, каждая из них должна загрузить свои данные, когда можно было бы 1 запросом загрузить данные сразу для всех.

    Вот как раз для этого агрегаты и нужны
    Ответ написан
  • Бывает ли разделенная модель в ddd?

    @ddd329
    В DDD это нормально определить одно и тоже понятие в разных моделях. В любой книге по DDD написано про ограниченные контексты, как раз для этого они и придуманы
    Ответ написан
    Комментировать
  • DDD, aggregate root, entity, repository?

    @ddd329
    Ну тогда АГРЕГАТ будет состоять из одной СУЩНОСТИ - City
    Ответ написан
  • Как следует организовать работу с entity?

    @ddd329
    Сущности и агрегаты нужны для реализации бизнес-логики, чтобы ты не смог в базу данных записать недостоверную и/или противоречивую информацию, и все!
    На экране ты отображаешь не сущности и агрегаты, а скорее информацию о них... Когда ты думаешь о выводе данных на экран, то не должен даже мыслить агрегатами, потому как агрегаты являются единицами изменения, а не порция для отображения.
    Поэтому можешь обращаться на прямую в БД с запросом выдать тебе информацию, или создать отдельную Модель Чтения, и через ORM читать данные.

    Создавать сущность LocalizedDisease не имеет смысла, так как не реализует новое поведение. Вообще сущность это в идеале только поведение, и не важно какие у него данные, то есть принцип здесь - "Говори а не спрашивай"
    Ответ написан
    Комментировать
  • Как правильно валидировать атрибуты сущности?

    @ddd329
    Привет!

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


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

    Как быть если ошибка в нескольких атрибутах сущности?


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

    Дублировать валидацию на клиенте и сервере не хочется


    Дублировать валидацию можно, если она общеизвестная, например ФИО или email-адрес, зачем перепадать эти значения на сервер, когда в браузере можно выполнить их полноценную валидацию, что повысит время отклика UI. А если логика специфичная, что чаще и бывает, то бизнес-правила должны "лежать" на уровне домена, и не выше.

    В общем, мне известно два варианта создания сущностей: используя только публичный конструктор, или используя фабрику(factory). Если я вас правильно понял, то у вас имеется форма с полями для заполнения их значениями, которые являются атрибутами какой-то сущности?
    Здесь могут быть два сценария, первый: когда сущность, а точнее АГРЕГАТ, извлекается из репозитория с целью редактирования, то здесь все так, как вы описали выше: неверное значение атрибута - выбрасываем исключение.
    И второй сценарий - создание сущности. Нигде нельзя получить доступ к невалидной сущности, созданной с помощью оператора new DomainObject() кроме как фабрики. Поэтому создавайте фабрику, которая позволяет строить вашу сущность, а точнее АГРЕГАТ, по шагам. Для этого примените паттерн проектирования СТРОИТЕЛЬ (Builder). В конце вызовите метод Build(), который и вернет вам валидный АГРЕГАТ.
    Что качается промежуточных результатов "строительства", то для их получения используйте паттерн проектирования СНИМОК (Memento), например вот так: var snapshot = domainObjectFactory.GetSnapshot();, где snapshot обычная DTO-ошка, которая содержит значения атрибутов сущностей и списки ошибок, валидность и т.д. Ну а дальше смотрите сами как быть, если вы на клиента передаете ViewModel-s, то используя snapshot создавайте модели представления и дальше их на UI пользователя.
    Ответ написан
    Комментировать
  • DDD, Aggregate root без ORM, как сохранять?

    @ddd329
    Без ORM, есть простые шаблоны. Твой репозиторий имеет метод Save, не важно обновил или создал новый АГРЕГАТ, все это передаешь методу Save, т.е. один метод вместо двух - Add и Delete. Допустим, ты обновляешь АГРЕГАТ, который состоит из трех сущностей, а в базе существуют три таблицы, т.е. каждая сущность маппиться на свою таблицу. Та сущнсость которая представляет корень АГРЕГАТА, будет использовать оператор UPDATE в SQL запросе, а дочерние сущности надо удалить (DELETE FROM..) и вставить заново(INSERT INTO). Все это делается в одной транзации базы данных, никакой вам Unit Of Work не нужен...

    Попробуйте...
    Ответ написан
    Комментировать
  • Всегда ли объект должен валидным?

    @ddd329 Автор вопроса
    Да, вопрос как раз об Entity и ValueObject'ы.

    Я пишу код на C#, но не суть... Я уже пробовал регистрационный номер выразить в коде через ValueObject, который бы занимался валидацией входной строки, и всегда создавался валидным. По началу казалось мне все проще, я проверял входную строку регулярным выражением, но этого оказалось мало.
    Входная строка, которая представляла регистрационный номер состоит из трех частей, первая часть это бизнес-направление, вторая часть вид документа и третья часть это порядковый номер, т.е. надо еще проверять существует ли бизнес-направление и вид документа, да и еще глобальную уникальность самого номера. Я сомневаюсь что этим всем должен заниматься ValueObject т.к. требуется обращение к Repository.

    Может сделать так: вынести класс Document в отдельную сборку Domain, выставить у свойства RegNumber модификатор доступа internal, чтобы клиентский код, например Presenter, не смог на прямую устанавливать значения. Ввести доменную службу DocumentService и в нем реализовать логику присвоения регистрационного номера, здесь как раз будет и парсинг строки, и проверка всех частей номера в базе данных обращение к которой будет осуществляться через репозиторий?
    Ответ написан
  • Как проще через JS менять атрибуты элемента SVG?

    @ddd329
    Ответ написан
    Комментировать
  • Как присвоить картинке определенный класс при нажатии?

    @ddd329
    Оберни каждый radio с картинкой в некий контейнер(например 'item')
    <div class="item">
      <label>
        <div class="images"><img src="tovar1_price.png"></div>
        <input type="radio" name="wpcc_structure[2]" value="300" checked class="wpcc_jq_action wpcc_jq_action_2" data-type="radio" data-fid="2" data-data="data"> Стартовый набор
      </label>
    </div>


    <script>
      $( '.item' ).on( 'click', '.images', function( e ) {
        e.stopPropagation();
        
        var
          $item = $( e.delegateTarget ),
          $img = $( this );
        
        $item.find( 'input[type="radio"]' ).prop( 'checked', true );
        
        $img.addClass( 'active' );
        
      });
      
      $( '.item' ).on( 'change', 'input[type="radio"]', function( e ) {
        e.stopPropagation();
        
        var
          $item = $( e.delegateTarget ),
          $img = $item.find( '.images' ),
          checked = $( this ).prop( 'checked' );
          
        if( checked ){
          $img.removeClass( 'active' );
        }
        else {
          $img.addClass( 'active' );
        }
        
      });
    </script>
    Ответ написан
    Комментировать
  • Как сравнить два массива?

    @ddd329
    1-ое проверяешь размерность, если не совпадает значит не равны. Если совпадает, надо как-то отсортировать и первый и второй массив, а потом поэлементно сравнивать. На вскидку примерно так...
    А если элемент массива сам является массивом его тоже сравнивать?
    Ответ написан
    Комментировать
  • Как пропарсить количество символов после точки?

    @ddd329
    Без регулярки:
    function isValid(str){
      var
        lastIndex = str.length - 1,
        findIndex = str.indexOf('.'),
        count = null;
        
    	if( findIndex == -1 ){
      	return true;
      }
      else {
      	count = lastIndex - findIndex;
      	return count == 1 || count == 2;
      }
    }
    
    console.log(isValid('123')) //true
    console.log(isValid('123.')) //false
    console.log(isValid('12.3')) //true
    console.log(isValid('1.23')) //true
    console.log(isValid('0.123')) //false
    console.log(isValid('1.100')) //false
    Ответ написан