Вадим Мартынов @Vadimyan
Программист
Информация
- В рейтинге
- 1 313-й
- Откуда
- Ростов-на-Дону, Ростовская обл., Россия
- Дата рождения
- Зарегистрирован
- Активность
Специализация
Backend Developer, Community manager
Lead
C#
.NET Core
Database
High-loaded systems
Designing application architecture
Database design
C++
Python
SRE
Этой зимой у нас пока что не было снега и не было ниже -5, чаще около нуля. При этом, для меня Ростовский мокрый туманный ветреный 0 холоднее сухого солнечного Екатеринбуржских -15. Это подтверждают и некоторые ребята из Екб, хотя объяснить на словах это не очень просто.
А ещё все по-разному переносят жару и холод. Мне не холодно почти никогда, но я в +3 заматываюсь в шарф «по глаза», шапку и куртку потеплее. Холод можно фиксить одеждой. А летом бороться с той же неделей, когда темпаратура выше +35 практически невозможно — очень легко получить обезвоживание и сопутствующие ему симптомы (головную боль, тепловой удар). Да, у нас примерно в 100% квартир стоит кондиционер, иногда несколько. Да, у нас расход топлива в авто повышается не зимой, а летом, опять из-за кондиционера.
Про климат и комфортные условия для жизни можно говорить достаточно много и я осознанно не раздувал саму статью этой темой как очень индивидуальной.
Как-то предлагал вместо утомительных распросов о «поиске подмассива с заданной суммой элементов» и «разворота односвязного списка» отбирать людей по росту — брать только тех, кто выше 180см., так как корреляция такая же очевидная. Не прижилось.
Вы предлагаете не поклоняться бездумно принципам SOLID и иметь критический взгляд на ООП, но не используете этот критический взгляд сами, трактуя принципы дословно без объектно-ориентированного мышления.
SOLID, в частности, ИМХО, рассказывает, как структурировать код таким образом, чтобы он вёл себя предсказуемо при модификации и переиспользовании, был тестируемым и, часто, простым для восприятия. OCP, например, позволит не сломать существующий код и избавит от мучительного регрессионного тестирования.
Статья могла бы стать полезной с реальными примерами неправильного применения и понимания SOLID.
Если же кандидат начинает тормозить, это признак губительной несамостоятельности и, возможно, излишней авторитарности со стороны руководителя проекта на предыдущих проектах.
Предлагаю ничью пока вы не расчехлили сохранение состояния конфигурации, а я MapReduce движок.
Можно добавлять сколько угодно много CanExecute, проверяться будут все, можно добавлять инвалидацию по изменению какого-либо свойства текущего объекта или другого объекта (а как это делается у вас?), можно добавлять блокировку по изменению состояния валидируемого объекта (см. выше), можно добавлять блокировку по состоянию IBusyItem — это такая обёртка над всем, что может блокировать что-либо (долгоиграющие операции).
Инвалидация от произвольных свойств нужна довольно часто, по состоянию валидации модели тоже приходится изменять доступность команд. Так что рекомаендую ещё эту идею в вашей библиотеке и для команд применить — очень красиво получается, если всё грамотно сделать.
Нет больше сил читать слово эвокатор — каждый раз перед глазами одно и то же:
Работает через тот же AfterNotify. В этой статье я специально опустил подробности о ViewModelBase, Workspaces для управления ж.ц. отображений и прочие свистелки, сделав упор на INPC.
Чего-то я здесь не понял, наверное. Речь идёт о зависимых и вычисляемых свойствах, ссылаясь на ту же исходную статью (сейчас я думаю, что можно было взять пример из неё ради сравнения), это, например, сумма заказа. Но иногда у нас есть агрегирующая ViewModel, которая зависит от внутренних VM. Это тоже пример вычисляемых свойств. Да, MultiBinding тоже есть, но под него всегда нужен конвертер и это переносит ближе к View нашу взаимосвязь. А View должна быть глупой.
С командами история отдельная и решений тоже достаточно. Видел даже патченный CompositeCommand из Prism, который делает RaiseCanExecuteChanged по движению мыши. Производительность — давай, до свидания.
Вау, похоже на ту самую задачу, которую уже давно решили. Это не просто ссылки, механизм DX действительно использовался наряду с [StorableSetting]. DX сохранял данные о положении окон в MDI-приложении (без написания дополнительного кода, в данном случае мы помечали View в View-first подходе пустым интерфейсом ради удобства), а дальше уже рекурсивно восстанавливались настройки дочерних View и ViewModel. Можно было переключаться в режим локального хранения настроек или хранения в БД для пользователя. Для сравнени с текстовым редактором в системе было 10^7 строк кода. Пометить интерфейсом View, добавить атрибуты, всё. При необходимости можно использовать методы BeforeRestoreLayout, AfterRestoreLayout для кастомизации, которая была нужна в 5-10 случаях. Можно через StorableSetting проводить явную инициализацию формы при вызове, но это уже несколько другая история.
Соответственно, довод о неявном сохранении большого количества настроек здесь неактуален — для визуального состояния всё так и есть. А в логическом для крупных систем всё может быть на столько запутано, что стоит ли надеется на неявное сохранение?
Может быть не стоит сериализовать (и вообще делать Serializable) вьюмодели и проблемы с вызовом конструктора с параметрами исчезнут? Со сломанными тестами вопрос спорный, в моём случае тесты не соберутся, в вашем упадут при прогоне (т.к. объект окажется недоинициализирован) с NullReferenceException. Тут уж каждому своё.
Я не вижу смысла спорить. Я верю, что для ваших задач ваше решение подходит, а руки уже согнулись в нужную сторону для применения описанных техник. Мои руки согнуты в другую сторону. И сломаны в нескольких местах. И поменяны местами. И необязательно друг с другом.
Просто собственный Application framework это всегда что-то текучее и нужно гнуть его под задачи непрерывно, а не наоборот.
Первым делом, что касается инициализации и применения сомнительного дополнительного метода, то это классическая проблема, решаемая при помощи автофабрик. Для Unity такой прелести нет, но на самом деле есть. И всё это можно получить без сомнительного ServiceLocator в лице Store. У вас ещё и тестируемость усложняется, поскольку внешние зависимости инжектируются мимо конструктора.
Что касается умного состояния и его сохранения. Наследование? Ни за что. В тот момент, когда вам будет необходимо отнаследоваться от стороннего класса и иметь умное состояние — всё рухнет. Вот тут есть небольшая попытка осмысления сохранения настроек, есть и гораздо более развитые библиотеки для этого, работающие на основе атрибутов [StorableSetting], которые позволяют совсем не писать код сохранения и легко разделяют сохраняемые и несохраняемые поля. Серьезно, только представьте, достаточно пометить свойство атрибутом. А сохранение и восстановление встраивается в механизм навигации, т.е. при создании View/ViewModel. Не забудьте только про рекурсивный обход объектов, состояние дочерних ViewModel и их свойств тоже нужно сохранять и восстанавливать.
Глобально, мне не нравится, что Exposable предлагает писать код сверх нужного. Нужно имплементировать Expose(), то есть аналог Initialize(). До вызова этого метода объект непригоден к работе, то есть нужно делать дополнительные проверки того, что объект уже инициализирован. Если встроить поддержу Exposable в using(), то сама необходимость его не совсем ясна. Вызывать Expose() в конструкторе? Чем он тогда будет лучше самого конструктора? У вас поддержка на уровне библиотеки через Store, это как вызов в конструкторе, только можно забыть и инициализировать объект второй раз явно. Или где-то он будет создаваться через new и окажется не инициализирован. Я понимаю, контракты, но зачем усложнять то, что и так просто сделать. Мне интересен реальный пример, оправдывающий такой overhead. Он у вас есть? Из проекта, из кода, чтобы без Exposable было сложнее, чем с ним.
Не стоит пытаться спорить с lair, достаточно просто сравнить его статьи и комментарии.
Спасибо за комментарий.
Мне нравится прозрачность с точки зрения именно вызова сервисов с клиента — если не брать в рассчет авторизацию, достаточно знать только про то, как пользоваться ServiceExecutor, а с ним напутать сложно.
Что касается эффективного использования и небольших проектов, конкретно эти 2 сборки удалось прикрутить к застарелому приложению на .net 4.0 на Prism с десятком модулей, совсем непростым взаимодействием с wcf и совершенно запутанной работой с сессиями. Это было сделано для быстрого управления конфигурацией и тестов производительности с разными настройками, и с задачей такое решение справилось. То есть, даже в отрыве от остальной инфрастуктуры — работает. Я бы назвал это даже «из коробки».
Стало интересно о реализации вызова wcf-сервисов из других wcf-сервисов, что если добавить клиентскую регистрацию на сервер? Оказалось, что работает:
Я боюсь подумать сейчас о расширенных сценариях, но решение есть. Как и у некоторых других задач, которые могут стать перед пользователем. Я тоже порекомендовал в статье использовать исходный код вместо пакета.
Ещё раз хочу сказать, что сложно пытаться сделать всеохватывающее решение — кому-то из моих коллег хватает простой реализации подобия ServiceExecutor:
Мне нравятся идеи сокрытия сложности. Да, иногда для этого нужно написать больше кода, но в конечном счёте какой-нибудь UnitOfWorkAttribute для метода, открывающий и завершающий (если вызывающий метод не был тоже помечен как [UnitOfWork]) или откатывающий при ошибке транзакцию при выходе из метода — того стоит.
Для типовых приложений, когда сервер и клиент являются по сути одним приложением, описанное мной решение подходит. При этом не важно intranet или internet используется для передачи. Да, в обычном сценарии сборка с OperationContract не добавляется на клиент из-за использования Proxy, туда идёт только DataContract.
Если у сервера и клиента жизненные циклы различаются, они лежат в разных решениях, то можно использовать привлекательный путь web api. Или распространять сборку контрактов через nuget. Или применять классический подход.
Я не пытаюсь сказать, что статья описывает золотой молоток, которого так долго ждали. Для наших задач подходит исходная или немного модифицированная версия библиотеки Rikrop.Core.Wcf. В тоже время я с интересом наблюдаю за библиотекой Boilerplate, которая тоже не является всеобъемлющим решением и, к сожалению, не столь модульна (я бы с удовольствием использовал репозитории и UoF оттуда), но является отличным инструментом для своего круга задач.
Диапазон для 4.0 выставить можно, поскольку известна последняя доступная версия для .net 4.0. Для 4.5 нужно ставить максимальной текущую доступную версию и обновлять по мере выхода новых версий. Возможно, есть другой путь или это лучшее решение?
Напишу сюда список хотелок, которые тормозят лично меня.
1. Импорт sln/csproj.
2. Экспорт sln/csproj.
3. Профили среды. Это значит, что если я запускаю Consulo под Win и создаю C# проект, то по-умолчанию очевидно выставить целевой платформой .net. Или предложить пользователю выбор из имющихся вариантов сразу. Windows это тоже приоритетная платформа :)
Это всегда можно взять и реализовать самому, но лучше дать возможность каждому заниматься тем, что у него получается. Вы не думали ещё раз на эту тему?