Как стать автором
Обновить
157
0
Pavel B. Novikov @pnovikov

.NET-разработчик

Отправить сообщение

Я вот искал себе в команду фронтендера — опросил десяток знакомых на предмет "а как их собеседовать?". Семеро мне сказали — "ищи того, кто хорошо шарит в JS, остальное фигня".

Ну вот знаете, всё ведь от человека зависит в конце концов. Можно и на голом JS запилить, а можно взять что-то чтобы поднять скорость.


Мне вот, короче, кажется что перед тем как использовать фреймворки — стоит какое-то время позапиливать сайтики на голом JS и HTML. Просто чтобы иметь представления о проблемах, которые фреймворки решают.

Я на чистом TS написал целый фреймворк для датагридов с 0 зависимостей. Что я сделал не так? :)

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


Вы хотите обставить всё так что мол на сервере OrdersService и на клиенте OrdersService с теми же методами и работают они одинаково, но эта абстракция течёт по той причине что сериализовывать stateful-объекты вы не можете и если таковой возвращает серверный OrdersService, то при попытке вызвать этот метод на клиенте произойдёт ошибка. Уже не говоря о том, что надо помечать все модели DataContract-атрибутами и писать портянку WCF-конфигурации в конфиге, иначе чуда не случится. Плюс разный контракт ошибок: если нет связи с сервером то выкинется соответствующий эксепшон в то время как на сервере такового не может произойти по определению.


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

В этой ситуации делается так:


  • на сервере: несколько каналов (база данных там, или что у вас), несколько сервисов для работы с ними.
  • на клиенте: один канал (Server), один аспект для WCF, но я бы сделал RPC-аспект (думаю над ним), одним из рантаймов которого был бы WCF (который уже мало кто использует).

На сервере пишем OrderService как показано в статье. Для клиента можем генерить обвязки к ним тем же самым tt, которые пускают запросы к серверу через аспект (чтобы работал перехват данных — см. следующую статью). Вероятно вместо tt можно использовать типы (надо смотреть на конкретику).


Клиентское приложение будет получать свой собственный OrderService, который сгенерен для него по образу и подобию серверного.


Что такое в вашей терминологии «клиентская логика»?

Вот это вот.


И, кстати, зависимость на сборку с сервером (или же промежуточную сборку с интерфейсами, необходимую и клиенту и серверу) нужна как раз в вашей схеме.

Да, логику с клиентской (а не серверной) логикой, содержащий набор сервисов, работающих с сервером как с каналом через WCF — придётся подключать к клиентскому приложению.

linq

Послушайте, LINQ в Tecture — это сугубо opt-in ORM-аспекта. Вам не обязательно его использовать, но если используете то рантайм должен поддерживать его целиком. В данном случае я использую рантайм, основанный на EF для этого. Если бы у меня его не было — то я бы не смог запустить приложение.


В остальном — я ещё раз подчеркну что LINQ (а точнее его expression) прежде всего — это про конструирование запроса и хранение информации о нём. Не о выполнении. Выполнение LINQ-запроса легко делегируется другой части системы, что в ORM-аспекте и сделано.


Кстати, вы не задумывались сделать их instance методами?

А в чём профит? Я вижу в такой декомпозиции два возможных профита:


  • моки. В Tecture не нужны (см. следующую статью);
  • возможность изменить реализацию ОДНОГО КОНКРЕТНОГО запроса. Такая необходимость происходит крайне редко, но и в Tecture она возможна — LINQ-запросу можно задать маркер (скажем через тот же метод .Describe) и уже на уровне рантайма вставить хук — мол — если пытаются выполнить такой-то запрос — сделать вот так-то.

Просто если следовать этой логике, то и методы в духе Where, Select, Join в LINQ так же стоило бы сделать instance-методами, но MS так не сделали по одной простой причине: смысл такой декомпозиции стремится к нулю при гигантских накладных расходах.


Методические рекомендации к использованию вашей архитектуры требует вынесения всех запросов в слой query или допустимо фигачить мимо этого слоя?

Нет "слоя" query. Слоёв по сути три — приложение, аспекты и рантайм. Запросы и команды — это разделение как бы "по другой оси координат". Т.е. есть часть системы, где пишут, а есть — где читают. By design у вас просто нет возможности нафигачить "мимо слоя". То есть можно, но это довольно сложно и вряд ли пользователь будет нарочно извращаться чтобы это сделать.

Нет. В Server и его аспекты вы оборачиваете всю коммуникацию с сервером поверх WCF или что там у вас.

Будет что-то в духе


var b = new TectureBuilder();
b.WithChannel<Server>(x=> { x.UseServer("127.0.0.1", 8080); });
var tecture = b.Build();
tecture.Let<OrdersService>().AddLine();
Проблема-то достаточно старая, решение такое лежит на поверхности, и тоже уже давно есть реализации

А можно ссылку? А то что-то мне не по глазам.
Так же подчеркну: я не делаю что-то принципиально новое и уникальное: просто раскладываю по полочкам старое и существующее.


To().Add(new Order()) отвалится

Он не может отвалиться потому что, простите, ничего не делает кроме создания команды и заталкивания её в очередь.


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


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


Сложность-то лежит как раз в разработке каналов-адаптеров

Я и не отрицаю. Задача состояла в том, чтобы чётко разделить реализацию каналов-адаптеров и реализацию бизнес-логики. Не вижу ни одной причины, по которой можно сказать что эта задача не решена.


Если вы декомпозируете работу с внешними каналами по моей схеме — у вас сразу появляется чёткое понимание что надо сделать: реализовать раннеры для таких-то команд, реализовать методы таких-то аспектов для запросов. Хоть в джиру готовые задачи закатывай.


То есть можно работать по крайней мере в понятных примитивах, а не нырять в неизвестность при встрече с каждой внешней системой.

В клиентском приложении всё так же — у вас есть один канал (сервер) + по вкусу локальный кэш — второй канал. Не вижу противоречий. WCF/SOAP — это уже вкусовщина на уровне рантайма в моей терминологии.


Вроде натягивается и даже не как сова на глобус.

Мне этот подход чем-то де-факто напомнил… FoxPro на NoSQL. Прикольно.

Всю первую часть предыдущей статьи я рассказывал, что канал может абстрагировать любую внешнюю систему. Странно, что вы увидели только БД. Тем более странно, что вы увидели только одну БД, когда я говорю что в качестве рантайма используется EF.Core, который поддерживает как минимум три базы.


И вся логика начинается с фразы From<Db>

С From<Db> начинаются только запросы и только к базе данных. Только к той, которую вы привязали к каналу Db.


это просто иная разновидность EF

Мимо. Обёртка для DirectSQL, кстати, есть.


очереди СМЭВ

Делаете аспект СМЭВ, подключаете его к любому каналу и погнали.


В остальном — см. вот этот комментарий и мой ответ на него.

Ещё есть using без скоупа с последних версий C#. Я вот в тестах использую такой. В общем есть много способов обыграть, аж глаза разбегаются. И это главное. :)

Спасибо. .Annotate — extension-метод для команды (как и .Describe для запроса) — вы можете без труда ввести свою систему именования прямо поверх них.


по дефолту так, а если хочется уровень Debug то эдак

Можно использовать #ifdef

Я думал о том, чтобы добавить такую опцию, но забегался и забыл. Сделать такую обёртку нетрудно руками.


Но это в любом случае opt-in, потому что имея BeginTrace/EndTrace проще вычленять хитрые куски логики, когда например начало в контроллере, а конец — внутри сервиса до первого сэйва.

А их пишет только вон тот опытный бородач

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


Или потянут?

Я сделаю всё от меня зависящее чтобы потянули. Сейчас немного разгребусь с текучкой и напишу детальные пошаговые инструкции-чеклисты по написанию аспектов и рантаймов. Мне сложно оценить сложность такой задачи — как по мне она довольно лёгкая и творческая. Плюс аспекты вполне могут кочевать из проекта в проект — почему нет?


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


Вы ведь не в одиночку будете это обкатывать?

С коллегой :)

Спасибо за отзыв.


Трэйс прямо божественен

В имейте в виду только что в него попадают все действия с каналами. То есть совсем все. Будет у вас кэш — факт записи в него тоже свалится в трейс. Хотя в целом трейс вполне можно отфильтровать руками и сделать свой Explain, включив туда только то, что интересно.


Насколько покрывают корнер кейсы

То, что я делаю называется data-driven testing или table-driven testing. Такие тесты не покрывают совершенно все corner case-ы — вы должны сделать это сами, но в смысле не руками, а подбить правильные тестовые данные и вводные, чтобы у вас проверялись все ветки. Ну то есть условно регистрируйте в своей админке юзера с одними правами — пробуете из теста залогиниться и удалить файл, захватываете занные. Заводите юзера с другими правами — пробуете то же самое ещё раз, захватываете данные.


На реальных проектах вам наверняка с этим поможет QA. То есть корнер-кейсы за вас не откроют, но уже открытые помогут оформить.


идеальный стэйктрейс вызова

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

Сделаю и добавлю отдельно. Просто я ж гифки записывал, там немного "декорации" есть :)

Информация

В рейтинге
Не участвует
Откуда
Новосибирск, Новосибирская обл., Россия
Зарегистрирован
Активность