На данный момент проект находится в активной разработке.
Как только мы сделаем релиз, с удовольствием, расскажем о проекте и его бизнес задачах на Хабре и сделаем кроссылки между статьями.
Причин по которым было разработано собственное приложение несколько:
1) Цель любой компании, в первую очередь, привлекать клиентов именно к своей продукции. Одним из наиболее удобных способов является разработка собственных сервисов и услуг, позволяющих визуализировать возможности конкретной техники.
Конечно можно загрузить бесплатно базы и в Dialux, но там имеется большое множество светотехники различных производителей (порядка 400), а чтобы получить преференции в установке своих баз, производитель должен выплачивать определенную сумму ежегодно.
2) Dialux профессиональная программа, которая может быть достаточно сложна для освоения, и зачастую она излишняя для расчета определенного круга задач.
В этом случае удобнее использовать приложение, специально разработанное для этих целей.
3) У Dialux в данный момент отсутствует мобильная версия и веб-сервисы, поэтому проще и быстрее загрузить приложение Light-in-Night, и сделать расчет освещения на планшете.
В принципе вы правы и для получения физически достоверного освещения именно так и нужжно поступать. Но в данном случае задача получается более упрощенной: Поскольку по госту есть требования минимальной освещенности, то достаточно подсчитать именно интенсивность прямого света, без учета переотраженния, что гарантированно обеспечит освещенность не ниже нормы.
Естетсвенно, можно попытаться сэкономить на освещении и попробовать рассчитать все с учетом переотражений, но это для этого нужно учитывать множество параметров и характеристик каждого конкретного помещения, что конечно экономически не целесообразно и не возможно без дополнительных измерений
Наскольку знаем, компания рассматривала возможность добавления каталогов сторонних производителей, так что возможно эта функциональность и появится в будущем.
«Бэтмен» появился случайно, но так понравился, что решили оставить в статье именно эту диаграмму.
Да, мы пробовали различные реализации Material Design для React, многие из них очень хороши. Но первая версия Material Design слишком сильно заточена под мобильные девайсы, а мы чаще работаем с десктопными веб-приложениями со сложным UI. Ant Design больше для этого подходит.
Про кинект в статье как раз упомянуто и использовали его для экспериментов. Однако заказчику требовалось простое и дешевое решение в виде отдельного модуля. Также изначально высоте подвеса и направление камеры было непоределено и могло достигать 10 и более метров. Соответственно кинект уже становится недостаточным для анализа.
Аналогично использование камер intel real sense не входило в сферу наших интересов, поскольку мы должны были встраивать наши алгоритмы в то, что имелось у заказчика.
Вообще Shadertoy настоящий кладез информации, а на сайте Inigo Quilez (если не ошибаюсь один из создателей Shadertoy) можно найти кучу очень интересных практических алгоритмов
Вы конечно правы, апрохимация в ряд Тейлора вполне может заменить синус. Он в данном случае нужен для получения просто псевдослучайного значения в любом интервале входных данных. Более того можно избавится от динамического бранчинга, если просто синус заменить на более упрощенное frac((x + x*x)/6.28) например. Но тем не менее изначальная проблема остается и увеличение скорости даже с 1 до 3 фпс сильно не поможет
1. Какую ответственность покажет фабрика? (Да и зачем для достаточно простых DTO фабрика?) То, что в контроллере используются команды/запросы? А из переданного диспетчера это будет не ясно?
2. Чем передача множества обработчиков вместе с возможными другими зависимостями, которые не относятся к CQRS, упростит чтение контроллера. Может, наоборот — усложнит? (Не считая того, что если контроллер содержит слишком много зависимостей, то, возможно, он делает слишком много, и стоит выделить дополнительный контроллер под более конкретные задачи, или же объединить часть зависимостей в одном высокоуровневом компоненте (вроде того же диспетчера)).
3. Из методов и названия контроллера не будет ясно, какие действия он производит?
Во-первых мы прибегаем к антипаттерну диктатор (по Марку Симену), когда зависимости мы создаем напрямую через new. На мой взгляд было бы уместнее использовать что-то вроде абстрактной фабрики запросов
Теперь мы вынуждены зависеть от фабрики, да и как она будет создавать объекты запросов/команд? Неужели new так плох?
Ну и в плане класса диспетчера, который по факту тоже является антипаттерном сервислокатор, он создает кажующуюся простоту контроллера. На самом деле он не уменьшает количество зависимостей ( и как следствие сложность) класса, он просто скрывает их реальное количество
Диспетчер делегирует вызов обработчиков по переданному сообщению, используется ли в нём Service Locator или нет — это не важно, он оперирует только определенным списком обработчиков. По этому поводу есть довольно интересная статья (англ.).
В итоге мы жертвуем простотой класса с точки зрения понимания его обязанностей и, как следствие, эффективностью рефакторинга. Было бы рациональнее внедрять конкретные обработчики через конструктор, при этом класс стал бы гораздо понятнее
Это хоть и допустимо, но не эффективно, т.к. стоит учитывать, что количество обработчиков может быть неопределенным, тем более если речь идет о рефакторинге.
Тогда может использоваться async/await, в этом случае метод интерфейса IQueryHandler должен будет возвращать Task<>. Для браузера же особой разницы не будет, т.к. он всё так же будет ожидать ответа.
public interface IQueryHandler<in TQuery, out TResult> where TQuery : IQuery<TResult>
{
Task<TResult> Execute(TQuery query);
}
public async Task<TResult> Execute(...)
{
var result = await GetSomething(...);
return result;
}
Вот абстракции и потекли. Не, я, конечно, за предгенерацию id, но это далеко не всегда возможно.
Как и строгое следование принципам CQS. Все сводится к балансу между жестким следованием принципами и производственной необходимостью, и какие последствия это может за собой повлечь.
Идентификатор элемента очереди. Или вы исповедуете принцип «с моей стороны вылетело, а дальше судьба команды меня не волнует»?
Зависит от реализации.
В простом случае команда вполне может вернуть статус выполнения успешно/неуспешно.
В другом случае команда может послать событие, что создание пользователя завершилось успешно, или не успешно, если по какой-то причине выполнить команду не удалось, и затем как-либо оповестить пользователя.
Или вообще без оповещения пользователя, вызывающему коду может лишь понадобиться знать, смогла ли команда выполниться или нет, чтобы, например, попытаться её выполнить снова в случае неудачного выполнения (типа недоступности сервера для отправки email).
CQRS в этом плане выступает как основа для подобных действий.
Ну так сами себе же создали проблемы :-) Если бы команда сразу же и возвращала данные свежесозданного пользователя или запросы могли сходить в основную базу и заполнить кеш, то таких проблем бы не было.
Потому что БД для чтения используется для повышения производительность запросов на чтение, а не записи, в первой ссылке в источниках об этом рассказывается подробнее.
UX меняется в случае использования CQRS с разными БД или Event Sourcing.
И как потом найти свежесозданного пользователя, если команда не будет возвращать нам его id?
Генерировать Id перед созданием пользователя, если только это не автоинкремент в БД (возможные проблемы с которым уже не относятся к CQRS).
Не отбрасывает. Возвращается либо id создаваемого пользователя, либо id асинхронной операции. Иначе о результате команды можно узнать лишь как-нибудь косвенно.
Если используется обычный async/await, то да. Если же команда обрабатывается в очереди, то здесь не получится что-либо вернуть.
Можем. Создаём 2 соединения: из одного читаем, в другое пишем. Оба соединения могут быть легко инкапсулированы в одном субд адаптере, позволяя программисту вообще не думать о том, что у него есть 2 базы.
Если только эти БД обновляются одновременно, но обычно БД для чтения обновляется позже, через какое-то время после изменений в БД для записи, иначе в ней пропадет смысл при её частом обновлении. То есть не получится сразу после создания пользователя получить по нему данные, его просто еще не будет существовать.
То есть достаточно назвать метод «TryChangeEmail», который пытается изменить email и возвращает статус изменения, и вашей проблемы с недопониманием что делает метод не будет. Разделение на 2 метода тут не требуется.
Конечно, в случае такого простого примера это может и не понадобиться.
Основная суть заключается в том, чтобы в подобных ситуациях было контролируемое разделение. В качестве другого примера можно взять более сложную и довольно типичную задачу: имеется метод, в котором идет создание нового пользователя, а после этого метод возвращает связанный с ним объект или его Id. Тем самым смешиваются команда и запрос.
На что это влияет? Это сразу отбрасывает возможность асинхронной операции, а это означает, что пользователь будет вынужден ждать, пока завершится операция, и вернется результат. Т.к. мы вынуждены возвращать результат сразу после команды, мы не сможем, например, добавить дополнительную БД, которая бы хранила и возвращала данные для запросов, а команды бы выполнялись на другой БД, тем самым распределяя нагрузку.
Иными словами, чем сложнее логика, тем больше эти и какие-либо другие факторы будут сказываться как на производительности, так и на сложности самого приложения.
Командам как правило необходимо делать запросы в процессе работы. И какой толк в этом случае от разделения команд и запросов, если они всё равно получаются сильно связанными?
В CQRS предлагается стремиться к тому, чтобы команда (или запрос) выполняла только строго определенную задачу, а вот сама команда уже может являться частью какой-либо бо́льшей задачи.
То есть все необходимые запросы и валидация должны быть сделаны до того, как команда начнет выполняться, и ей должны быть переданы необходимые данные. Тем самым будут иметься отдельные Query, вместо того, чтобы выполнять их в команде.
Из сравнений наиболее актуальных версий (PostgreSQL 9.5b1 и MongoDB 3.2.0) можно упомянуть доклад на PgConf.Russia 2016 где рассматриваются результаты выполнения основных операций и рассказывается, почему и при каких условиях так получилось.:)
С нетерпением ждём сравнение производительности MongoDB 3.4 и PosgreSQL 9.6!
А Вы не пробовали знаки препинания расставлять когда задание пишете? «Но для кратных трём значений «Fizz» вместо номера...» пять минут потратил чтобы понять, что же здесь хотят)
Архитектуру взаимодействия проектировали не мы. К моменту старта разработки Android-клиента уже был реализован web-клиент. Поэтому пришлось реализовывать такое решение.
Как только мы сделаем релиз, с удовольствием, расскажем о проекте и его бизнес задачах на Хабре и сделаем кроссылки между статьями.
1) Цель любой компании, в первую очередь, привлекать клиентов именно к своей продукции. Одним из наиболее удобных способов является разработка собственных сервисов и услуг, позволяющих визуализировать возможности конкретной техники.
Конечно можно загрузить бесплатно базы и в Dialux, но там имеется большое множество светотехники различных производителей (порядка 400), а чтобы получить преференции в установке своих баз, производитель должен выплачивать определенную сумму ежегодно.
2) Dialux профессиональная программа, которая может быть достаточно сложна для освоения, и зачастую она излишняя для расчета определенного круга задач.
В этом случае удобнее использовать приложение, специально разработанное для этих целей.
3) У Dialux в данный момент отсутствует мобильная версия и веб-сервисы, поэтому проще и быстрее загрузить приложение Light-in-Night, и сделать расчет освещения на планшете.
Естетсвенно, можно попытаться сэкономить на освещении и попробовать рассчитать все с учетом переотражений, но это для этого нужно учитывать множество параметров и характеристик каждого конкретного помещения, что конечно экономически не целесообразно и не возможно без дополнительных измерений
«Бэтмен» появился случайно, но так понравился, что решили оставить в статье именно эту диаграмму.
Аналогично использование камер intel real sense не входило в сферу наших интересов, поскольку мы должны были встраивать наши алгоритмы в то, что имелось у заказчика.
Особенно нравится вторая демка, как наиболее реалистичное. Хотя меня больше всего впечатлило https://www.shadertoy.com/view/XdsGDB
Вообще Shadertoy настоящий кладез информации, а на сайте Inigo Quilez (если не ошибаюсь один из создателей Shadertoy) можно найти кучу очень интересных практических алгоритмов
1. Какую ответственность покажет фабрика? (Да и зачем для достаточно простых DTO фабрика?) То, что в контроллере используются команды/запросы? А из переданного диспетчера это будет не ясно?
2. Чем передача множества обработчиков вместе с возможными другими зависимостями, которые не относятся к CQRS, упростит чтение контроллера. Может, наоборот — усложнит? (Не считая того, что если контроллер содержит слишком много зависимостей, то, возможно, он делает слишком много, и стоит выделить дополнительный контроллер под более конкретные задачи, или же объединить часть зависимостей в одном высокоуровневом компоненте (вроде того же диспетчера)).
3. Из методов и названия контроллера не будет ясно, какие действия он производит?
Теперь мы вынуждены зависеть от фабрики, да и как она будет создавать объекты запросов/команд? Неужели
newтак плох?Диспетчер делегирует вызов обработчиков по переданному сообщению, используется ли в нём Service Locator или нет — это не важно, он оперирует только определенным списком обработчиков. По этому поводу есть довольно интересная статья (англ.).
Это хоть и допустимо, но не эффективно, т.к. стоит учитывать, что количество обработчиков может быть неопределенным, тем более если речь идет о рефакторинге.
Как и строгое следование принципам CQS. Все сводится к балансу между жестким следованием принципами и производственной необходимостью, и какие последствия это может за собой повлечь.
Зависит от реализации.
В простом случае команда вполне может вернуть статус выполнения успешно/неуспешно.
В другом случае команда может послать событие, что создание пользователя завершилось успешно, или не успешно, если по какой-то причине выполнить команду не удалось, и затем как-либо оповестить пользователя.
Или вообще без оповещения пользователя, вызывающему коду может лишь понадобиться знать, смогла ли команда выполниться или нет, чтобы, например, попытаться её выполнить снова в случае неудачного выполнения (типа недоступности сервера для отправки email).
CQRS в этом плане выступает как основа для подобных действий.
Потому что БД для чтения используется для повышения производительность запросов на чтение, а не записи, в первой ссылке в источниках об этом рассказывается подробнее.
UX меняется в случае использования CQRS с разными БД или Event Sourcing.
Генерировать Id перед созданием пользователя, если только это не автоинкремент в БД (возможные проблемы с которым уже не относятся к CQRS).
Если используется обычный async/await, то да. Если же команда обрабатывается в очереди, то здесь не получится что-либо вернуть.
Если только эти БД обновляются одновременно, но обычно БД для чтения обновляется позже, через какое-то время после изменений в БД для записи, иначе в ней пропадет смысл при её частом обновлении. То есть не получится сразу после создания пользователя получить по нему данные, его просто еще не будет существовать.
Конечно, в случае такого простого примера это может и не понадобиться.
Основная суть заключается в том, чтобы в подобных ситуациях было контролируемое разделение. В качестве другого примера можно взять более сложную и довольно типичную задачу: имеется метод, в котором идет создание нового пользователя, а после этого метод возвращает связанный с ним объект или его Id. Тем самым смешиваются команда и запрос.
На что это влияет? Это сразу отбрасывает возможность асинхронной операции, а это означает, что пользователь будет вынужден ждать, пока завершится операция, и вернется результат. Т.к. мы вынуждены возвращать результат сразу после команды, мы не сможем, например, добавить дополнительную БД, которая бы хранила и возвращала данные для запросов, а команды бы выполнялись на другой БД, тем самым распределяя нагрузку.
Иными словами, чем сложнее логика, тем больше эти и какие-либо другие факторы будут сказываться как на производительности, так и на сложности самого приложения.
В CQRS предлагается стремиться к тому, чтобы команда (или запрос) выполняла только строго определенную задачу, а вот сама команда уже может являться частью какой-либо бо́льшей задачи.
То есть все необходимые запросы и валидация должны быть сделаны до того, как команда начнет выполняться, и ей должны быть переданы необходимые данные. Тем самым будут иметься отдельные Query, вместо того, чтобы выполнять их в команде.
С нетерпением ждём сравнение производительности MongoDB 3.4 и PosgreSQL 9.6!
P.S. информацию по этой теме также можно почитать на хабре.