Как стать автором
Обновить
88
2.4
Вадим Мартынов @Vadimyan

Программист

Отправить сообщение
На 1 неделю и не каждый год. Вообще, про климат много спорили в статье про Краснодар. Потому что это очень субъективная история.

Этой зимой у нас пока что не было снега и не было ниже -5, чаще около нуля. При этом, для меня Ростовский мокрый туманный ветреный 0 холоднее сухого солнечного Екатеринбуржских -15. Это подтверждают и некоторые ребята из Екб, хотя объяснить на словах это не очень просто.

А ещё все по-разному переносят жару и холод. Мне не холодно почти никогда, но я в +3 заматываюсь в шарф «по глаза», шапку и куртку потеплее. Холод можно фиксить одеждой. А летом бороться с той же неделей, когда темпаратура выше +35 практически невозможно — очень легко получить обезвоживание и сопутствующие ему симптомы (головную боль, тепловой удар). Да, у нас примерно в 100% квартир стоит кондиционер, иногда несколько. Да, у нас расход топлива в авто повышается не зимой, а летом, опять из-за кондиционера.

Про климат и комфортные условия для жизни можно говорить достаточно много и я осознанно не раздувал саму статью этой темой как очень индивидуальной.
>> Хорошо, но фильтровать их такими собеседованиями суть подбрасывать монетку
Как-то предлагал вместо утомительных распросов о «поиске подмассива с заданной суммой элементов» и «разворота односвязного списка» отбирать людей по росту — брать только тех, кто выше 180см., так как корреляция такая же очевидная. Не прижилось.
Только ситхи всё возводят в абсолют.

Вы предлагаете не поклоняться бездумно принципам SOLID и иметь критический взгляд на ООП, но не используете этот критический взгляд сами, трактуя принципы дословно без объектно-ориентированного мышления.

SOLID, в частности, ИМХО, рассказывает, как структурировать код таким образом, чтобы он вёл себя предсказуемо при модификации и переиспользовании, был тестируемым и, часто, простым для восприятия. OCP, например, позволит не сломать существующий код и избавит от мучительного регрессионного тестирования.

Статья могла бы стать полезной с реальными примерами неправильного применения и понимания SOLID.
ИМХО, правильный ответ — это наличие ответа. Уверенный ответ. В каждой команде роли распределяются по-своему, но нужно представлять те обязаности, которые можешь взять на себя и которые видишь перспективным и выгодным для команды на себя брать.
Если же кандидат начинает тормозить, это признак губительной несамостоятельности и, возможно, излишней авторитарности со стороны руководителя проекта на предыдущих проектах.
AfterNotify(() => Kisses).Execute(() => 
{
    if (Kesses < 10) return;
    _myFirstCommand.RaiseCanExecuteChanged();
    _anotherOneCommand.RaiseCanExecuteChanged();
});

GetUserCommand = new RelayCommandBuilder<int>(async id => User  await userServiceExecutor.Execute(us => us.GetUser(id))).CreateCommand();

AfterNotify(() => Scene.Dimension).Execute(async () => await OnCombine(Scene.Dimension));

Предлагаю ничью пока вы не расчехлили сохранение состояния конфигурации, а я MapReduce движок.
Ок, раз речь зашла о командах. Вот такая реализация в Rikrop:
MyCommand = new RelayCommandBuilder(p => DoSomeWork(p)).AddCanExecute(p => p.ReadyToWork).InvalidateOnNotify(_myDependency, md => md.SomeProperty).AddBlocker(_myServiceExecutor).CreateCommand();

Можно добавлять сколько угодно много CanExecute, проверяться будут все, можно добавлять инвалидацию по изменению какого-либо свойства текущего объекта или другого объекта (а как это делается у вас?), можно добавлять блокировку по изменению состояния валидируемого объекта (см. выше), можно добавлять блокировку по состоянию IBusyItem — это такая обёртка над всем, что может блокировать что-либо (долгоиграющие операции).

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

Нет больше сил читать слово эвокатор — каждый раз перед глазами одно и то же:
image
via
verifiableObject.ForProperty(vo => vo.TotalSize).AddValidationRule(s => s > 20);
verifiableObject.ForObject().AddAsyncValidationRule(ct => ValidateLengthAsync(ct)).AlsoValidate(vo => vo.TotalSize);

Работает через тот же AfterNotify. В этой статье я специально опустил подробности о ViewModelBase, Workspaces для управления ж.ц. отображений и прочие свистелки, сделав упор на INPC.
Например, указывая в привязке Model.Property1.Property2.Property3 мы автоматически получаем отслеживание изменения в Property1, 2 и 3 одновременно.

Чего-то я здесь не понял, наверное. Речь идёт о зависимых и вычисляемых свойствах, ссылаясь на ту же исходную статью (сейчас я думаю, что можно было взять пример из неё ради сравнения), это, например, сумма заказа. Но иногда у нас есть агрегирующая ViewModel, которая зависит от внутренних VM. Это тоже пример вычисляемых свойств. Да, MultiBinding тоже есть, но под него всегда нужен конвертер и это переносит ближе к View нашу взаимосвязь. А View должна быть глупой.
С командами история отдельная и решений тоже достаточно. Видел даже патченный CompositeCommand из Prism, который делает RaiseCanExecuteChanged по движению мыши. Производительность — давай, до свидания.
В очередном проекте на 3 вкладки понадобилось менять доступность команд при изменении свойств, не являющихся параметрами этих команд. Вспомнил о старом друге и решил заодно поделиться им. Когда речь идёт о 500 строках кода — решение о добавлении новой зависимости для меня не является однозначным.
Это хабраблог Microsoft Россия. MS даже стрелки кидает на них как на отдельную организацию, если дело касается локальных сервисов/проектов. Так что если что, то будет «я — не я, статья не моя».
Не забудьте сохранить состояние как логическое (вкладки, текст), так и визуальное (размеры и положения окна, настройки шрифта, цвета).

Вау, похоже на ту самую задачу, которую уже давно решили. Это не просто ссылки, механизм DX действительно использовался наряду с [StorableSetting]. DX сохранял данные о положении окон в MDI-приложении (без написания дополнительного кода, в данном случае мы помечали View в View-first подходе пустым интерфейсом ради удобства), а дальше уже рекурсивно восстанавливались настройки дочерних View и ViewModel. Можно было переключаться в режим локального хранения настроек или хранения в БД для пользователя. Для сравнени с текстовым редактором в системе было 10^7 строк кода. Пометить интерфейсом View, добавить атрибуты, всё. При необходимости можно использовать методы BeforeRestoreLayout, AfterRestoreLayout для кастомизации, которая была нужна в 5-10 случаях. Можно через StorableSetting проводить явную инициализацию формы при вызове, но это уже несколько другая история.

Соответственно, довод о неявном сохранении большого количества настроек здесь неактуален — для визуального состояния всё так и есть. А в логическом для крупных систем всё может быть на столько запутано, что стоит ли надеется на неявное сохранение?
Может быть не стоит сериализовать (и вообще делать Serializable) вьюмодели и проблемы с вызовом конструктора с параметрами исчезнут? Со сломанными тестами вопрос спорный, в моём случае тесты не соберутся, в вашем упадут при прогоне (т.к. объект окажется недоинициализирован) с NullReferenceException. Тут уж каждому своё.

Я не вижу смысла спорить. Я верю, что для ваших задач ваше решение подходит, а руки уже согнулись в нужную сторону для применения описанных техник. Мои руки согнуты в другую сторону. И сломаны в нескольких местах. И поменяны местами. И необязательно друг с другом.

Просто собственный Application framework это всегда что-то текучее и нужно гнуть его под задачи непрерывно, а не наоборот.
Честно сказать, я не очень люблю читать комментарии lair к статьям по .net, поскольку считаю его безальтернативным скептиком («У вас всё плохо, но как хорошо я не скажу») но в данном случае я вынужден с ним согласиться. Здесь описан какой-то кошмар :)
Первым делом, что касается инициализации и применения сомнительного дополнительного метода, то это классическая проблема, решаемая при помощи автофабрик. Для Unity такой прелести нет, но на самом деле есть. И всё это можно получить без сомнительного ServiceLocator в лице Store. У вас ещё и тестируемость усложняется, поскольку внешние зависимости инжектируются мимо конструктора.
Что касается умного состояния и его сохранения. Наследование? Ни за что. В тот момент, когда вам будет необходимо отнаследоваться от стороннего класса и иметь умное состояние — всё рухнет. Вот тут есть небольшая попытка осмысления сохранения настроек, есть и гораздо более развитые библиотеки для этого, работающие на основе атрибутов [StorableSetting], которые позволяют совсем не писать код сохранения и легко разделяют сохраняемые и несохраняемые поля. Серьезно, только представьте, достаточно пометить свойство атрибутом. А сохранение и восстановление встраивается в механизм навигации, т.е. при создании View/ViewModel. Не забудьте только про рекурсивный обход объектов, состояние дочерних ViewModel и их свойств тоже нужно сохранять и восстанавливать.
Глобально, мне не нравится, что Exposable предлагает писать код сверх нужного. Нужно имплементировать Expose(), то есть аналог Initialize(). До вызова этого метода объект непригоден к работе, то есть нужно делать дополнительные проверки того, что объект уже инициализирован. Если встроить поддержу Exposable в using(), то сама необходимость его не совсем ясна. Вызывать Expose() в конструкторе? Чем он тогда будет лучше самого конструктора? У вас поддержка на уровне библиотеки через Store, это как вызов в конструкторе, только можно забыть и инициализировать объект второй раз явно. Или где-то он будет создаваться через new и окажется не инициализирован. Я понимаю, контракты, но зачем усложнять то, что и так просто сделать. Мне интересен реальный пример, оправдывающий такой overhead. Он у вас есть? Из проекта, из кода, чтобы без Exposable было сложнее, чем с ним.
Не стоит пытаться спорить с lair, достаточно просто сравнить его статьи и комментарии.
Мы используем такое решение для автофабрик. Да, вдохновлял Autofac, но на вкус и цвет последний не приглянулся, Unity как-то более поддерживаем сообществом.
Привет, Николай.
Спасибо за комментарий.

Мне нравится прозрачность с точки зрения именно вызова сервисов с клиента — если не брать в рассчет авторизацию, достаточно знать только про то, как пользоваться ServiceExecutor, а с ним напутать сложно.
Что касается эффективного использования и небольших проектов, конкретно эти 2 сборки удалось прикрутить к застарелому приложению на .net 4.0 на Prism с десятком модулей, совсем непростым взаимодействием с wcf и совершенно запутанной работой с сессиями. Это было сделано для быстрого управления конфигурацией и тестов производительности с разными настройками, и с задачей такое решение справилось. То есть, даже в отрыве от остальной инфрастуктуры — работает. Я бы назвал это даже «из коробки».
Стало интересно о реализации вызова wcf-сервисов из других wcf-сервисов, что если добавить клиентскую регистрацию на сервер? Оказалось, что работает:
public class CalculatorService : ICalculatorService
{
    private readonly IServiceExecutor<IAnotherService> _anotherServiceExecutor;

    public CalculatorService(IServiceExecutor<IAnotherService> anotherServiceExecutor)
    {
        _anotherServiceExecutor = anotherServiceExecutor;
    }

    public async Task<int> CalculateSqrSqr(int n)
    {
        return await _anotherServiceExecutor.Execute(service => service.Get(n*n));
    }
}

Я боюсь подумать сейчас о расширенных сценариях, но решение есть. Как и у некоторых других задач, которые могут стать перед пользователем. Я тоже порекомендовал в статье использовать исходный код вместо пакета.
Ещё раз хочу сказать, что сложно пытаться сделать всеохватывающее решение — кому-то из моих коллег хватает простой реализации подобия ServiceExecutor:
var sign = 
        WCFHelper<ISftService>
            .Execute("BasicHttpBinding_ISftService", serviceInstance => serviceInstance.Sign(dataToSign), exception => { });

Мне нравятся идеи сокрытия сложности. Да, иногда для этого нужно написать больше кода, но в конечном счёте какой-нибудь UnitOfWorkAttribute для метода, открывающий и завершающий (если вызывающий метод не был тоже помечен как [UnitOfWork]) или откатывающий при ошибке транзакцию при выходе из метода — того стоит.
Я могу только сказать, что у нас совершенно разный опыт разработки под .net. Это касается не только wcf, но и применения EF.
Для типовых приложений, когда сервер и клиент являются по сути одним приложением, описанное мной решение подходит. При этом не важно intranet или internet используется для передачи. Да, в обычном сценарии сборка с OperationContract не добавляется на клиент из-за использования Proxy, туда идёт только DataContract.
Если у сервера и клиента жизненные циклы различаются, они лежат в разных решениях, то можно использовать привлекательный путь web api. Или распространять сборку контрактов через nuget. Или применять классический подход.
Я не пытаюсь сказать, что статья описывает золотой молоток, которого так долго ждали. Для наших задач подходит исходная или немного модифицированная версия библиотеки Rikrop.Core.Wcf. В тоже время я с интересом наблюдаю за библиотекой Boilerplate, которая тоже не является всеобъемлющим решением и, к сожалению, не столь модульна (я бы с удовольствием использовал репозитории и UoF оттуда), но является отличным инструментом для своего круга задач.
Я приведу цитату из предыдущего поста:
Фиксированная версия Unity. Если в Nuget-пакете для 4.0 не указать версию явно, то nuget попытается зарезолвить последнюю версию, несмотря на то, что она несовместима с .net 4. Если кто-нибудь знает способ избавиться от этой проблемы, просьба сообщить в личку.

Диапазон для 4.0 выставить можно, поскольку известна последняя доступная версия для .net 4.0. Для 4.5 нужно ставить максимальной текущую доступную версию и обновлять по мере выхода новых версий. Возможно, есть другой путь или это лучшее решение?
Я привел последние два примера как раз для иллюстрации того, что не во всех сценариях библиотека позволяет делать меньше действий. Для разделения сервисов на несколько групп с разными настройками конфигурация подходит даже лучше. У нас просто не возникало таких потребностей, поэтому есть только базовые и не всегда удобные механизмы для этого (можно посмотреть реализацию ServiceHostManager или смириться и разделять на уровне контейнеров/проектов).
Нашёл довольно интересные идеи о репозиториях в соседней статье. Во-первых, созданием репозиториев управляет UoW, что подразумевает использование одного контекста всегда, Во-вторых, репозиторий представляется как интерфейс доступа к IQueryable Table. Вполне вероятно, что следующая версия библиотеки эти идеи реализует.
Я не о индивидуальном подходе имел в виду. О стандартном краудфандинге стоит ли думать не уверен, а вот список тикетов (фич, реквестов), которые, например, лично вам не критичны, но которые могут заинтересовать сообщество, с стоимостью их реализации, может быть интересен. С одной стороны есть возможность доната, но в каком-нибудь Paint.NET это просто способ поблагодарить разработчиков, а здесь это причастность к интересной или хотя бы потенциально интересной для донатера фиче.
Я всё ещё надеюсь увидеть когда-нибудь на странице проекта или среди постов на хабре ссылку на программу поощрения автора(ов). Тем более он же может стать и неким аналогом User voice. Например, я очень хотел бы использовать Consulo уже сейчас, но мир коммерческой разработки таков, что «дешевле» использовать VS. Я надеюсь, что фичи под заказ смогут популяризировать продукт, повлиять на его развитие и получить поддержку не только независимых разработчиков.
Напишу сюда список хотелок, которые тормозят лично меня.
1. Импорт sln/csproj.
2. Экспорт sln/csproj.
3. Профили среды. Это значит, что если я запускаю Consulo под Win и создаю C# проект, то по-умолчанию очевидно выставить целевой платформой .net. Или предложить пользователю выбор из имющихся вариантов сразу. Windows это тоже приоритетная платформа :)

Это всегда можно взять и реализовать самому, но лучше дать возможность каждому заниматься тем, что у него получается. Вы не думали ещё раз на эту тему?

Информация

В рейтинге
1 313-й
Откуда
Ростов-на-Дону, Ростовская обл., Россия
Дата рождения
Зарегистрирован
Активность

Специализация

Backend Developer, Community manager
Lead
C#
.NET Core
Database
High-loaded systems
Designing application architecture
Database design
C++
Python
SRE