Богдан Стефанюк

Заметки о программировании, путешествиях, плёнке и разных интересностях
Обо мне  •  Список заметок  •  Плёнка

Google Drive → OneDrive

Гугл диском пользуюсь на протяжении 4-5 лет. В целом всё устраивало, но вот время от времени появлялись проблемы, которые сильно мешали. Например, синхронизация файлов работала через раз, загружаю файл с телефона, а он только через полчаса появляется на компьютере, иногда нужно руками поменять любой файл через веб интерфейс, чтобы файл появился у меня на компьютере.

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

Начал искать замену. Dropbox для меня стал неюзабельным, кроме того, соотношение цены и фич не самое лучшее. В то же время на работе активно использовал корпоративный OneDrive. Решил присмотреть его в качестве облака для файлов.
 
В итоге собрал небольшую сравнительную табличку и по результатам которой решил переехать в OneDrive

Из минусов OneDrive можно отметить глючное приложение для mac. Синхронизирует — отлично, но вот интерфейс приложения тупит. Но я его почти никогда не открываю.

С другой стороны, мобильно приложение в OneDrive намного удобнее. Можно посмотреть файлы, которые ты расшарил и которые расширили тебе. Также радует наличие сканера документов прямо в приложении.

Прошло два месяца, OneDrive меня полностью устраивает. От Google Drive полностью не избавился, так как очень много людей его используют, в том числе их документы, да и я сам.

Жизненный цикл запросов в ASP.NET Core MVC

Жизненный цикл — это цепочка событий, этапов и компонентов, которые взаимодействуют друг с другом, чтобы обработать запрос пользователя и предоставить ему ответ.

Общий вид на жизненный цикл ASP.NET Core MVC приложений:

Он содержит в себе несколько этапов:

  • Middlewares
  • Routing
  • Controller Initialization
  • Controller action execution
  • Result Execution
  • View Rendering

Middlewares

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

В ASP.NET Core у нас есть 4 метода, с помощью которых мы можем создавать свои middlewares.

  • Use
  • Run
  • Map
  • MapWhen

Официальная документация

Routing

Маршрутизация позволяет найти для каждого URL подходящий обработчик, а также извлекает все параметры из URL и красиво их нам предоставляет. Для работы роутинга нам нужны две middleware:

  • UseRouting
  • UseEndpoints

Как все это работает?

UseRouting встраивает класс EndpointRoutingMiddleware, он смотрит на конечные точки, которые есть в приложении и выбирает подходящую. Выбор происходит на основании URL и заголовков. После того как нужный обработчик найден (Request delegate) его присваивают свойству Endpoint(IEndpointFeature) внутри текущего HttpContext. В дальнейшем мы можем получить его значения с помощью метода GetEndpoint.

UseEndpoints встраивает EndpointMiddleware. Он отвечает за выполнение установленной ранее конечной точки.

Официальная документация

Controller initialization

Для обеспечения работы контроллеров у есть два класса: ResourceInvoker, ControllerActionInvoker.

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

ControllerActionInvoker наследует ResourceInvoker и добавляет в него логику работы с контроллерами и их методами.

Каждый из этих классов содержит машину состояний, где каждое состояние отвечает за свой этап жизненного цикла контроллера.

Исходники классов можно посмотреть на github (ResourceInvoker, ControllerActionInvoker).

Action workflow

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

Общий вид этого жизненного цикла:

  • Фильтры авторизации
  • Фильтры ресурсов
  • Привязки моделей
  • Фильтры действий
  • Выполнение метода контроллера
  • Фильтры исключений
  • Фильтры результатов
  • Выполнение результата
  • Фильтры результатов

Детальнее про фильтры можно почитать на метаните.

Result execution

Методы контроллера возвращают объекты результата, которые в дальнейшем преобразовываются в соответствующее представление. Объект результата должен наследовать абстрактный класс ActionResult. Фреймворк предоставляет нам большое множество готовых классов.

Общий вид того как происходит рендеринг представлений:

Источники

Ilford HP5 Plus 400

Классическая черно белая пленка. Мелкозернистая, не имеет особых ограничений на условия съемки. Пушиться до 1600 ISO.

Semantica — тема для Visual Studio Code

Красивая тема редактора сильно влияет на удобство работы с кодом. Я перепробовал множество разных тем, сначала были тёмные, но спустя какое-то время я перешёл на светлые. Большинство тем меня не устраивали. Для меня важно чтобы: интерфейс не обращал на себя внимания, подсветка кода похожая на то что есть в обычной Visual Studio и Rider.

Однажды наткнулся на отличную тему Alabaster. Общая цветовая палитра мне зашла, но вот подсветка синтаксиса слишком минималистичная. В итоге решил на основе этой темы запилить свою. Добавил подсветку синтаксиса похожую на Visual Studio Light и Rider Light. В итоге получилась новая тема — Semantica.

Логотип темы.

Ссылки

Исходный код: https://github.com/teamkiller7112/vscode-theme-semantica
Маркетплейс: https://marketplace.visualstudio.com/items?itemName=bogdanstefanjuk.theme-semantica

Скриншоты

PS

Замечания или пожелания оставляйте на гитхабе. Если тема понравилась — поставьте звездочку в репозитории

В качестве шрифта советую использовать JetBrains Mono.

Ссылки, часть 22

Случайное плёночное фото, просроченная Agfa Color 100.

Инфостиль в заголовках задач

Данный текст взят из канала Фёдора Борщёва

Я не сильно докапываюсь к чистоте текста в задачах и служебной переписке: конечно клёво, когда люди пишут понятно, но не всем нужно это учить: нафига какому-нибудь руководителю логистической службы писать тексты на 8 баллов главреда? Главное, чтобы он мог хоть как-то сформулировать сигнал, что болит — а дальше придут опытные продакты/проджекты и всё выяснят.

Но есть одно место, где я жёстко включаю Ильяхова — это заголовки задач в трекере. На сколько вы бы захотели работать в команде, которая целый день занимается какой-нибудь «необходимостью реализовать новый механизм построения отчётности» и, чтобы не произносить это дерьмо в слух, называет задачи по номерам (типа «Как там задача 1238?»). Я — не хотел бы.

Вот пара правил для заголовков задач, которые помогут не превращать трекер в бухгалтерский отчёт:
— Из заголовка чётко понятно, что нужно сделать. Не «доработать логику корзины», а «Сделать, чтобы при удалении последнего товара корзина очищалась».
— Никакой воды: смело рубить всякие «необходимо реализовать» и «отсутствие возможности».
— В заголовке есть понятные для всей команды ключевые слова. Если задача про вкладку Логистика, то так и писать «логистика», а не «интерфейс менеджера-логиста».
— Если задача мало декомпозирована («привести в порядок учёт зарплаты») то заголовок должен описывать следующий понятный шаг, к примеру «Понять, почему заказ 100500 не пробросился в 1с» или «сделать кнопку „не согласен с расчётом“.

Update: для любой проблемы уже давно написан специализированный сервис. Мне тут подсказали http://bugred.ru, который как главред, только для задач в трекере.

Fujifilm Superia 200 (просрочена 2011 год.)

Купил немного просроченной пленки от Fuji. Протестировал как она снимает если работать по номиналу. Фото делал на Konica Autoreflex T3.

Мой рабочий стол

Долго откладывал обустройство рабочего стола. Раньше сидел на кухне, так как основная работа была в офисе. На время карантина перешёл на удаленную работу, потребность в нормальном рабочем месте стала очень остро. Решил запариться и сделать так, как всегда хотел.

Стол

Начал поиски с большого и удобного стола. Изначально думал взять стол с регулируемой высотой, но цены на порядок выше, в итоге решил искать обычный стол. На столе будут располагаться: ноутбук, рабочий ноутбук, монитор. А также удобно вести записи в блокнот и параллельно работать с компьютером.

Выбор пал на Loft design L-3p.

Выбором доволен. За ним удобно сидеть, он большой. Минус только один — отверстие под провода находятся посередине, что мешает поставить монитор ровно по центру. Вижу два решения: использовать кронштейн для монитора или поставить монитор над отверстием, а провода пустить за стол, собрав стяжками.

Монитор

Монитор долго не выбирал, взял по совету моего друга Dell P2419HC на 24 дюйма, хотя сейчас понимаю, что стоило взять на 27. Основной критерий — поддержка type-c с возможностью power delivery (одним кабелем заряжает ноутбук и передаёт картинку).

Периферия

Выбирал среди продуктов компания logitech, так как люблю эту компанию. Про их мышь я уже рассказывал в посте Logitech M590 или лучшая мышка для mac. Требования к клавиатуре: беспроводная, поддержка нескольких компьютеров. В итоге выбрал Logitech K380. Она стильно выглядит, цена приятная и очень удобная.

Стул

Так как большую часть времени я сижу, нужно подобрать удобный и надёжный стул. Посоветовался с друзьями и выбрал DxRacer Sentinel.

Итого

Мне очень нравится мое новое рабочее место. Конечно есть еще возможности к улучшениям, но пока их можно отложить на потом.

Мой сетап:

  • Монитор Dell P2419HC
  • Клавиатура Logitech K380
  • Мышь Logitech M590
  • Коврик для мыши Razer Goliathus Terra Large Speed

Что можно улучшить?

  • Решить вопрос с организацией проводов.
  • Купить хорошую аудио аудиосистему.
  • Попробовать поставить стол лицом к комнате, а не к стене.
  • Купить небольшой стеллаж и поставить сбоку стола. На нем расположу все свои книги и другие айтемы.

Интересные находки в сети

Случайное плёночное фото, сегодня это Kodak Ektachrome E100.

Асинхронное программирование в C#

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

Что такое асинхронность?

Асинхронность — выполнение программного кода, не блокирующее потоки во время ожидания.

Например: делаем запрос в бд для получения некоторых данных.
У нас есть поток и запрос, который выполняет этот поток. При синхронном выполнении наш поток будет ждать, пока БД не ответит. В асинхронном случае наш поток будет выполнять другой запрос, пока БД обрабатывает текущий.

TAP

С приходом .NET Framework 4.0 появился новый способ для работы с асинхронностью — TAP. По сути, это набор классов, которые предоставляют более удобный интерфейс для работы с асинхронным кодом. Но мы всё ещё можем использовать старые подходы: APM и EAP. Но Майкрософт советует использовать TAP.

Центральным классов в TAP является Task. Он описывает отдельную задачу, выполнение которой может завершиться в какой-то момент. 

Детальнее про подходы работы с многопоточностью.

Как создать задачу?

Фреймворк предоставляет множество способов для создания и запуска задач, а также оборачивания старого кода (APM и EAP).

Фабрики запущенных задач

Task.Run(Action/Func)
Task.Factory.StartNew(Action/Func)

Фабрики завершенных задач

Task.FromResult(Result)
Task.FromCanceled(Result)
Task.FromException(Result)
Task.CompletedTask

Конструктор

var task = new Task(Action/Func)
task.Start()

Фабрики для оборачивания в таски

Task.Factory.FromAsync(APM pattern)
TaskCompletionSource(EAP, APM, etc)

Класс TaskScheduler

Класс, который содержит стратегию запуска и планирования задач Task. Существуют две стандартные реализации: ThreadPoolTaskScheduler и SynchronizationContextTaskScheduler. Первая запускает задачи с помощью пула потоков, а вторая — использует текущий контекст синхронизации.

Чтобы указать планировщику, что наша задача продолжительная мы можем использовать флаг TaskCreationOptions.LongRunning (указывается при создании задачи). Это гарантирует, что под нашу задачу выделиться отдельный поток и в него не будут планироваться продолжения других операций.

У каждого потока есть свой «текущий» контекст, который необязательно должен быть уникальным. Иногда нам нужно, чтобы завершение или продолжение асинхронной операции выполнялись в том же контексте, откуда было запущено. Например, приложения с UI. После нажатия на кнопку мы запускаем асинхронную операцию, результат которой нужно вывести на экран. Но мы не сможем получить доступ к UI элементу, так как он находится в другом потоке. Для этого нам нужно запустить обновление данных в контексте UI потока. Именно для этого и нужен контекст синхронизации.

Контекст синхронизации при работе с Task и Thread

Комбинирование задач

Есть ситуации, когда нам нужно ожидать выполнения нескольких задач, для этого мы можем использовать комбинаторы задач.

Task.WaitAll();
Task.WaitAny();
Task.WhenAll();
Task.WhenAny();

Но нужно быть внимательным, так как WaitAll и WaitAny являются блокирующими операциями. Вместо них желательно использовать WhenAll и WhenAny.

Как получить результат?

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

Блокирующее получение результата:

.Result
.GetAwaiter().GetResult() - //лучше не использовать так как этот метод предназначен для компилятора, а не для нас.
.Wait()

Асинхронное:

await

Что такое sync over async deadlock?

Продолжение задач

Есть ситуации, когда нам нужно выполнить несколько операций одну за одной. Для этого у нас есть метод ContinueWith, с помощью которого можно построить цепочку продолжений.

Пример:

var task = Task.Run(() => Console.WriteLine("Async task"));
var nextTask = task.ContinueWith((prevTask) => {
	Console.WriteLine("Continuation");
});
nextTask.ContinueWith((prevTask) => {
	Console.WriteLine("Last Continuation");
});

Мы можем настраивать условия продолжения используя класс TaskContinuationOptions. С его помощью мы можем строить дерево задач, запускать продолжения по условиям и т. д.

Официальная документация

Обработка исключений

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

Обработка исключения при использовании await:

try
{
	await Task.Run(() => { throw new Exception(); });
}
catch (Exception e)
{
	// 
}

По умолчанию ContinueWith выполняется независимо от того произошло ли исключение в предыдущей задаче. Но мы можем его настроить двумя способами: в самом продолжении проверить предыдущую задачу или сделать отдельное продолжение, которое будет вызвано только при возникновении исключения.

Task.Run(() => { throw new Exception(); })
	.ContinueWith((prev) => {
		if (prev.IsFaulted)
		{
			//
		}
	});

Task.Run(() => { throw new Exception(); })
	.ContinueWith((prev) => {
		
	}, TaskCreationOptions.OnlyOnfaulted);

Стоит избегать асинхронных методов, которые ничего не возвращают (async void). Так как при возникновении исключения внутри метода, мы просто не сможем его обработать.

Комбинаторы задач также по-разному предоставляют исключения:

  • Task.WaitAll() — вернёт AggregateException;
  • Task.WhenAll() — вернёт только первое исключение;

Отмена задач

Если нам нужно отменить выполнение асинхронной задачи мы можем воспользоваться классом CancellationToken. Про него я рассказывал раньше.

async/await

Основная идея этого подхода заключается в написании асинхронного кода как синхронного. Это позволило создать более дружелюбный интерфейс для работы с асинхронностью.

Что делает async?

  • Создаёт машину состояний, которая обрабатывает все продолжения и синхронизации.
  • Разрешает использовать await.
  • Позволяет передавать вверх по стеку результат и исключения, используя Task.

Что делает await?

  • Позволяет не блокирующее ожидать результат.
  • Запуск продолжения в нужном потоке.
  • Возвращает результат или исключение.

Заблуждения по поводу await

  • Запускает операцию асинхронно.
  • Являться синтаксическим сахаром над Task.ContinueWtih.
  • Обязательно запускает продолжение в новый поток.
  • Всегда работает асинхронно.

Советы

  • Не используйте комбинацию async void — вы не сможете отловить исключение, а также ожидать выполнение метода.
  • Методы помеченные как async должны внутри себя содержать await.
  • Старайтесь вежде использовать не блокирующее ожидание await вместо блокирующего.
  • Для выполнения продолжительных операций используйте Task.Factory.StartNew вместе с TaskCreationOptions.LognRunning.
  • Используйте await t.ConfigureAwait(false) для библиотечного кода.
  • Не используйте совместно await и ContinueWith, так как они ничего не знают друг о друге.

Что осталось за кадром?

  • Асинхронные потоки
  • ValueTask
  • Progress

Ссылки

 Нет комментариев    721   4 мес   .net   c#
Ранее Ctrl + ↓