День пятьсот восемьдесят первый. #ЧтоНовенького
Полутип
Тип
16 бит в типе
- Знак: 1 бит
- Экспонента: 5 бит
- Значимые биты: 10 бит (с 1 неявным битом, который не хранится)
Несмотря на то, что значение состоит из 10 бит, общая точность на самом деле составляет 11 бит. Предполагается, что формат имеет неявный начальный бит, равный 1 (если в поле экспоненты не все нули, в противном случае 0).
Вот так в формате
- Биты экспоненты равны 01111 или 15 в десятичной системе. Биты экспоненты не представляют экспоненту напрямую. Вместо этого определяется смещение экспоненты, которое позволяет формату представлять как положительные, так и отрицательные значения экспоненты. Для типа
- Наконец, поскольку биты экспоненты (01111) не все равны 0, у нас есть неявный ведущий бит 1.
Итого:
Наименьшее положительное значение
В .NET 5.0 тип
Источник: https://devblogs.microsoft.com/dotnet/introducing-the-half-type/
Полутип
Тип
Half
– это 16-битное число с плавающей точкой (эквивалент binary16
в спецификации IEEE 754). То есть это половина от float
, и может представлять значения в диапазоне ±65504
. Один из основных вариантов использования типа Half
- экономия места для хранения, когда вычисленный результат не нужно сохранять с полной точностью. Многие системы уже используют преимущества типа Half
: машинное обучение, графические карты, новейшие процессоры, нативные библиотеки SIMD и т.д.16 бит в типе
Half
делятся на:- Знак: 1 бит
- Экспонента: 5 бит
- Значимые биты: 10 бит (с 1 неявным битом, который не хранится)
Несмотря на то, что значение состоит из 10 бит, общая точность на самом деле составляет 11 бит. Предполагается, что формат имеет неявный начальный бит, равный 1 (если в поле экспоненты не все нули, в противном случае 0).
Вот так в формате
Half
представляется число 1:0 01111 0000000000 = 1- Ведущий бит (знак) равен 0 – положительное число.
- Биты экспоненты равны 01111 или 15 в десятичной системе. Биты экспоненты не представляют экспоненту напрямую. Вместо этого определяется смещение экспоненты, которое позволяет формату представлять как положительные, так и отрицательные значения экспоненты. Для типа
Half
смещение экспоненты равно 15. Истинная экспонента получается вычитанием: e = 01111(или 15) - 15(смещение) = 0.- Значение равно 0000000000. Оно представляет собой числитель дроби, в знаменателе которой 1024 (2^10). В нашем случае числитель равен 0. Но, если бы значение было, например, 0000011010 (26 в десятичной системе), то дробь представляла бы собой 26/1024 или 0,025390625.
- Наконец, поскольку биты экспоненты (01111) не все равны 0, у нас есть неявный ведущий бит 1.
Итого:
0 01111 0000000000 = 2^0 * (1 + 0/1024) = 1Общая формула значения Half:
-1^(знак) * 2^(экспонента - 15) * (неявный бит + (значение/1024))Особый случай для экспоненты 00000:
-1^(знак) * 2^(-14) * (0 + (значение/1024))Примеры
Наименьшее положительное значение
0 00000 0000000001 = -1^(0)*2^(-14)*(0 + 1/1024) ≈ 0,000000059604645Наибольшее число
0 11110 1111111111 = -1^(0)*2^(15)*(1+1023/1024) ≈ 65504"Бесконечность"
1 11111 0000000000 = -БесконечностьОсобенность формата в том, что он определяет как положительный, так и отрицательный 0:
0 11111 0000000000 = +Бесконечность
1 00000 0000000000 = -0Преобразования в/из float/double
0 00000 0000000000 = +0
float f = (float)half;Любое значение
Half h = (Half)floatValue;
Half
может быть представлено как float
/double
без потери точности. Однако обратное неверно. В .NET 5.0 тип
Half
- это прежде всего промежуточный тип, для которого не определены арифметические операторы. Он поддерживает только парсинг, форматирование и сравнение. Для всех арифметических операций потребуется явное преобразование в float
/double
. В будущих версиях будет рассмотрено добавление арифметических операторов непосредственно в Half
и использование его в вычислениях напрямую.Источник: https://devblogs.microsoft.com/dotnet/introducing-the-half-type/
This media is not supported in your browser
VIEW IN TELEGRAM
День пятьсот восемьдесят второй. #TipsAndTricks
Повышаем продуктивность в Visual Studio.
33. Фильтр Решения
В крупном корпоративном приложении у вас может быть и 20, и 30 проектов, и иногда вам не нужно загружать их все. В Visual Studio 2019 вы можете выгрузить эти проекты, затем щелкнуть правой кнопкой мыши на решении, и выбрать пункт «Сохранить как Фильтр Решения» (Save as Solution Filter). Укажите имя, и сохраните файл. Если вы откроете файл фильтра решения, студия не загрузит выгруженные проекты.
34. Повторное использование кода
Допустим, вы хотите повторно использовать фрагмент кода. Это легко сделать, выбрав соответствующий фрагмент, и сохранить его на панели инструментов (Toolbox). Чтобы открыть Toolbox, нажмите
Источник: https://devsuhas.com/2020/01/19/visual-studio-2019-tips-and-tricks/
Повышаем продуктивность в Visual Studio.
33. Фильтр Решения
В крупном корпоративном приложении у вас может быть и 20, и 30 проектов, и иногда вам не нужно загружать их все. В Visual Studio 2019 вы можете выгрузить эти проекты, затем щелкнуть правой кнопкой мыши на решении, и выбрать пункт «Сохранить как Фильтр Решения» (Save as Solution Filter). Укажите имя, и сохраните файл. Если вы откроете файл фильтра решения, студия не загрузит выгруженные проекты.
34. Повторное использование кода
Допустим, вы хотите повторно использовать фрагмент кода. Это легко сделать, выбрав соответствующий фрагмент, и сохранить его на панели инструментов (Toolbox). Чтобы открыть Toolbox, нажмите
Ctrl+Alt+X
, выберите фрагмент кода и просто перетащите его туда.Источник: https://devsuhas.com/2020/01/19/visual-studio-2019-tips-and-tricks/
День пятьсот восемьдесят третий. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
58. Тестировщики - твои друзья
Их отдел может называться Контролем Качества (Quality Control) или Обеспечением Качества (Quality Assurance), но многие программисты называют их занозой в ж…. Обычно программисты враждуют с людьми, которые тестируют их программы. «Они слишком придираются» и «Они хотят, чтобы всё было идеально» - частые жалобы. Звучит знакомо?
Не знаю почему, но у меня всегда был другой взгляд на тестировщиков. Может быть, потому что «тестером» на моей первой работе была секретарша. Маргарет была очень приятной женщиной, которая поддерживала работу офиса и пыталась научить пару молодых программистов, как вести себя профессионально перед клиентами. У неё также был дар находить за считанные минуты любую ошибку, даже самую неочевидную.
Тогда я работал над программой, написанной бухгалтером, который думал, что он программист. Стоит ли говорить, что с программой были серьёзные проблемы. Когда я думал, что исправил кусок программы, Маргарет пыталась его использовать, и, чаще всего, он отказывал каким-то новым образом после всего лишь пары нажатий клавиш. Временами это расстраивало и бесило, но она была таким приятным человеком, что я и не думал винить её за то, что она выставляла меня в плохом свете. В конце концов, настал день, когда Маргарет смогла запустить программу, забить в неё документ, распечатать его и закрыть. Я был в восторге. Более того, когда мы установили программу на машину нашего клиента, всё заработало. Клиенты никогда не сталкивались с проблемами, потому что Маргарет помогала мне находить и исправлять их.
Вот почему тестировщики - ваши друзья. Вы можете думать, что тестировщики пытаются унизить вас, сообщая о незначительных проблемах. Но когда клиенты в восторге от того, что их не беспокоили все те «мелочи», которые QA заставил вас исправить, тогда вы в глазах клиентов выглядите отлично.
Представьте себе: вы тестируете утилиту, которая использует «новейшие алгоритмы искусственного интеллекта» для поиска и устранения проблем состояния гонки в многопоточных приложениях. Вы запускаете её и сразу замечаете, что на заставке неправильно написано слово «интеллект». Немного неприятно, но это всего лишь опечатка, правда? Затем вы видите, что на экране настройки используются флажки там, где должны быть переключатели, а некоторые сочетания клавиш не работают. Понятно, что всё это не имеет большого значения, но по мере того, как ошибки накапливаются, вы начинаете задумываться о квалификации программистов. Если они не могут сделать простые вещи правильно, каковы шансы, что их программа действительно сможет найти и исправить что-то сложное?
Они могут быть гениями, которые настолько были сосредоточены на том, чтобы сделать свой ИИ безумно эффективным, что не замечали этих тривиальных вещей. А в отсутствие «придирчивых тестировщиков», указывающих на проблемы, в конце концов, проблемы нашли вы. А теперь вы ставите под сомнение компетентность программистов.
Итак, как бы странно это ни звучало, мерзкие тестировщики, у которых, как кажется, нет ничего важнее в жизни, чем найти каждый мельчайший недочёт в вашем коде, на самом деле ваши друзья.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Burk Hufnagel.
97 Вещей, Которые Должен Знать Каждый Программист
58. Тестировщики - твои друзья
Их отдел может называться Контролем Качества (Quality Control) или Обеспечением Качества (Quality Assurance), но многие программисты называют их занозой в ж…. Обычно программисты враждуют с людьми, которые тестируют их программы. «Они слишком придираются» и «Они хотят, чтобы всё было идеально» - частые жалобы. Звучит знакомо?
Не знаю почему, но у меня всегда был другой взгляд на тестировщиков. Может быть, потому что «тестером» на моей первой работе была секретарша. Маргарет была очень приятной женщиной, которая поддерживала работу офиса и пыталась научить пару молодых программистов, как вести себя профессионально перед клиентами. У неё также был дар находить за считанные минуты любую ошибку, даже самую неочевидную.
Тогда я работал над программой, написанной бухгалтером, который думал, что он программист. Стоит ли говорить, что с программой были серьёзные проблемы. Когда я думал, что исправил кусок программы, Маргарет пыталась его использовать, и, чаще всего, он отказывал каким-то новым образом после всего лишь пары нажатий клавиш. Временами это расстраивало и бесило, но она была таким приятным человеком, что я и не думал винить её за то, что она выставляла меня в плохом свете. В конце концов, настал день, когда Маргарет смогла запустить программу, забить в неё документ, распечатать его и закрыть. Я был в восторге. Более того, когда мы установили программу на машину нашего клиента, всё заработало. Клиенты никогда не сталкивались с проблемами, потому что Маргарет помогала мне находить и исправлять их.
Вот почему тестировщики - ваши друзья. Вы можете думать, что тестировщики пытаются унизить вас, сообщая о незначительных проблемах. Но когда клиенты в восторге от того, что их не беспокоили все те «мелочи», которые QA заставил вас исправить, тогда вы в глазах клиентов выглядите отлично.
Представьте себе: вы тестируете утилиту, которая использует «новейшие алгоритмы искусственного интеллекта» для поиска и устранения проблем состояния гонки в многопоточных приложениях. Вы запускаете её и сразу замечаете, что на заставке неправильно написано слово «интеллект». Немного неприятно, но это всего лишь опечатка, правда? Затем вы видите, что на экране настройки используются флажки там, где должны быть переключатели, а некоторые сочетания клавиш не работают. Понятно, что всё это не имеет большого значения, но по мере того, как ошибки накапливаются, вы начинаете задумываться о квалификации программистов. Если они не могут сделать простые вещи правильно, каковы шансы, что их программа действительно сможет найти и исправить что-то сложное?
Они могут быть гениями, которые настолько были сосредоточены на том, чтобы сделать свой ИИ безумно эффективным, что не замечали этих тривиальных вещей. А в отсутствие «придирчивых тестировщиков», указывающих на проблемы, в конце концов, проблемы нашли вы. А теперь вы ставите под сомнение компетентность программистов.
Итак, как бы странно это ни звучало, мерзкие тестировщики, у которых, как кажется, нет ничего важнее в жизни, чем найти каждый мельчайший недочёт в вашем коде, на самом деле ваши друзья.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Burk Hufnagel.
День пятьсот восемьдесят четвёртый. #ЗаметкиНаПолях
IAsyncDisposable
Интерфейс
IAsyncDisposable
В .NET Core 3 появился интерфейс
Использование
Вот простой пример использования новой конструкции
Интерфейс
Источник: https://khalidabuhakmeh.com/iasyncdisposable-dispose-resources-asynchronously
IAsyncDisposable
Интерфейс
IDisposable
существует с .NET Framework 1.0 и даёт нам возможность освобождать занятые ресурсы. using (var disposable = new Disposable()) { … }У
IDisposable
есть недостаток, который стал более очевидным с появлением Task
. Освобождение ресурсов происходит синхронно и может блокировать потоки. Хуже того, неправильная утилизация асинхронного ресурса может привести к взаимным блокировкам.IAsyncDisposable
В .NET Core 3 появился интерфейс
IAsyncDisposable
, который позволяет освобождать асинхронные ресурсы в методе DisposeAsync
, возвращающем ValueTask
:public interface IAsyncDisposable {Заметьте, что
ValueTask DisposeAsync();
}
IDisposable
и IAsyncDisposable
могут быть реализованы независимо друг от друга. Скорее всего, IAsyncDisposable
не реализует IDisposable
, потому что создатели не захотели создавать у разработчиков ложное впечатление, что по умолчанию во всех случаях есть синхронный вариант.Использование
Вот простой пример использования новой конструкции
await using
с IAsyncDisposable
. Сначала напишем класс, реализующий интерфейс:public class HotGarbage : IAsyncDisposable {Надо заметить, что раз класс реализует
public async ValueTask DisposeAsync() {
Console.WriteLine("Чем так пахнет?");
await Task.Delay(TimeSpan.FromSeconds(3));
Console.WriteLine("Выкидываем мусор");
}
public void Look() => Console.WriteLine("Хмм...");
}
IAsyncDisposable
, то, вероятно, он имеет зависимости, требующие асинхронного удаления. Использование:static async Task Main(string[] args) {Мы используем локальную функцию внутри метода
async Task Run() {
await using var hotGarbage = new HotGarbage();
hotGarbage.Look();
}
await Run();
}
Main
. Ключевые слова await using
полезны, чтобы уменьшить количество скобок в коде и снизить вероятность ошибки при рефакторинге. Запустив код, мы видим результаты нашего асинхронного удаления:Хмм...Итого
Чем так пахнет?
Выкидываем мусор
Интерфейс
IAsyncDisposable
должен упростить написание библиотек, которые имеют дело с операциями ввода-вывода. Авторы библиотек доступа к базам данных, обработки изображений и интернет-протоколов должны иметь возможность изящно избавляться от управляемых ресурсов, не опасаясь взаимных блокировок. Мы, как потребители библиотек, получаем приятный синтаксический сахар в виде конструкции await using
, что ещё больше упрощает код.Источник: https://khalidabuhakmeh.com/iasyncdisposable-dispose-resources-asynchronously
День пятьсот восемьдесят пятый. #ЧтоНовенького
Управляем Уровнем Анализа Кода в .NET5
В последних версиях .NET добавлены новые анализаторы кода, позволяющие вам автоматически находить скрытые недочёты в коде, которые могут приводить к ошибкам. При этом в анализаторы кода редко добавлялись новые предупреждения, т.к. это технически является критическим изменением для пользователей, установивших предупреждения как ошибки.
В .NET5 в компилятор C# добавлена настройка
Для предыдущих версий платформы уровень по умолчанию установлен на 4, что не мешает вам самостоятельно установить его в значение от 0 до 3.
Вот, как это сделать:
Наконец, можно задать значение none, означающее запрет новых предупреждений. В этом режиме вы не получите ни расширенного анализа, ни новых предупреждений компилятора. Это полезно, если вы переходите на более новую платформу, и пока не готовы разбираться с новыми предупреждениями.
Вот некоторые новые предупреждения на уровне анализа 5:
Источник: https://devblogs.microsoft.com/dotnet/automatically-find-latent-bugs-in-your-code-with-net-5/
Управляем Уровнем Анализа Кода в .NET5
В последних версиях .NET добавлены новые анализаторы кода, позволяющие вам автоматически находить скрытые недочёты в коде, которые могут приводить к ошибкам. При этом в анализаторы кода редко добавлялись новые предупреждения, т.к. это технически является критическим изменением для пользователей, установивших предупреждения как ошибки.
В .NET5 в компилятор C# добавлена настройка
AnalysisLevel
, позволяющая безопасно добавлять новые предупреждения в анализаторы. Уровень анализа по умолчанию для всех проектов на .NET5, будет установлен на 5. Это означает, что будут показываться новые предупреждения, введённые в .NET5.Для предыдущих версий платформы уровень по умолчанию установлен на 4, что не мешает вам самостоятельно установить его в значение от 0 до 3.
Вот, как это сделать:
<Project Sdk="Microsoft.NET.Sdk">Если вы всегда хотите использовать последний поддерживаемый уровень анализа, укажите значение latest. Также можно опробовать экспериментальные методы анализа, указав значение preview:
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AnalysisLevel>5</AnalysisLevel>
</PropertyGroup>
</Project>
<AnalysisLevel>latest</AnalysisLevel>Обратите внимание, что при этом результаты анализа могут различаться на разных машинах в зависимости от доступного на машине SDK и уровня анализа, который он предлагает.
Наконец, можно задать значение none, означающее запрет новых предупреждений. В этом режиме вы не получите ни расширенного анализа, ни новых предупреждений компилятора. Это полезно, если вы переходите на более новую платформу, и пока не готовы разбираться с новыми предупреждениями.
Вот некоторые новые предупреждения на уровне анализа 5:
CA1416
– Предупреждение: Код работает не на всех платформахCA2013
– Предупреждение: Не используйте ReferenceEquals
с типами-значениямиCA2200
– Предупреждение: Выбрасывайте исходное исключение, чтобы сохранить стек вызововCS0185
– Ошибка: lock
недопустим на нессылочных типахCS7023
– Ошибка: Недопустимо использовать as или is со статическими типамиCS8073
– Предупреждение: Выражение всегда ложь или истина Источник: https://devblogs.microsoft.com/dotnet/automatically-find-latent-bugs-in-your-code-with-net-5/
День пятьсот восемьдесят шестой. #TipsAndTricks
Как Обеспечить Одинаковый Стиль Кодирования в Ваших Проектах
У каждой компании/команды свой стиль программирования. Это касается именования, пробелов или использования функций языка. Вы используете табы или пробелы и сколько пробелов? Вы используете PascalCase или camelCase? Вы ставите нижнее подчёркивание перед именами полей? Вы используете
В проекте важно, чтобы все участники использовали общий стиль кодирования, чтобы ваша кодовая база оставалась согласованной. Также на код ревью это уменьшает количество комментариев по поводу добавления пробелов и прочих мелочей.
Файл .editorconfig
EditorConfig помогает разработчикам определять и поддерживать согласованные стили кодирования для разных редакторов и IDE. Проект EditorConfig – это специальным образом отформатированный файл с определениями стилей кодирования и набор плагинов для текстовых редакторов, которые позволяют редакторам читать этот файл и применять определённые в нём стили. Файлы EditorConfig легко читаемы и прекрасно работают с системами контроля версий.
EditorConfig поддерживается Visual Studio и JetBrains Rider изначально, а в Visual Studio Code через плагин.
Как это работает?
IDE ищет файл с именем
Создать файл
Вот несколько полезных ресурсов про .editorconfig в .NET:
- пример файла из проекта ProjectSystem
- документация по правилам .NET
Источник: https://www.meziantou.net/enforce-dotnet-code-style-in-ci-with-dotnet-format.htm
Как Обеспечить Одинаковый Стиль Кодирования в Ваших Проектах
У каждой компании/команды свой стиль программирования. Это касается именования, пробелов или использования функций языка. Вы используете табы или пробелы и сколько пробелов? Вы используете PascalCase или camelCase? Вы ставите нижнее подчёркивание перед именами полей? Вы используете
var
всегда или только когда тип очевиден? И ещё несколько вопросов подобного типа…В проекте важно, чтобы все участники использовали общий стиль кодирования, чтобы ваша кодовая база оставалась согласованной. Также на код ревью это уменьшает количество комментариев по поводу добавления пробелов и прочих мелочей.
Файл .editorconfig
EditorConfig помогает разработчикам определять и поддерживать согласованные стили кодирования для разных редакторов и IDE. Проект EditorConfig – это специальным образом отформатированный файл с определениями стилей кодирования и набор плагинов для текстовых редакторов, которые позволяют редакторам читать этот файл и применять определённые в нём стили. Файлы EditorConfig легко читаемы и прекрасно работают с системами контроля версий.
EditorConfig поддерживается Visual Studio и JetBrains Rider изначально, а в Visual Studio Code через плагин.
Как это работает?
IDE ищет файл с именем
.editorconfig
в корне вашего репозитория. Файл содержит инструкции для разных файлов проекта на основе шаблона подстановки. Есть глобальные инструкции, такие как indent_style
или indent_size
, и специальные инструкции для C#, такие как dotnet_sort_system_directives_first
. Вот пример:# Глобальные настройкиФайл
[*]
indent_style = space
# Файлы кода
[*.{cs,csx,vb,vbx}]]
indent_size = 4
insert_final_newline = true
charset = utf-8-bom
# Файлы проекта
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
indent_size = 2
# Специальные директивы для .NET
[*.{cs,vb}]
dotnet_sort_system_directives_first = true
dotnet_style_require_accessibility_modifiers = always:warning
# …
.editorconfig
помещается в репозиторий, поэтому каждый участник может использовать его для написания кода, соответствующего стилю кодирования. Кроме того, Visual Studio покажет меню быстрых правок и редактирования с советами по изменению кода в соответствии со стилем кодирования, определённым в файле конфигурации.Создать файл
.editorconfig
можно и в проводнике Windows, но Visual Studio может создать его для вас. Нажмите правой кнопкой на решение, выберите «Добавить Новый Элемент…» (Add New Item…), в появившемся окне найдите editorconfig File (.NET) на вкладке Общие (General).Вот несколько полезных ресурсов про .editorconfig в .NET:
- пример файла из проекта ProjectSystem
- документация по правилам .NET
Источник: https://www.meziantou.net/enforce-dotnet-code-style-in-ci-with-dotnet-format.htm
День пятьсот восемьдесят седьмой. #TipsAndTricks
Применение Единого Стиля Кодирования .NET в CI
В предыдущем посте было описано использование файла
Другой вариант – использовать
Применение Единого Стиля Кодирования .NET в CI
В предыдущем посте было описано использование файла
.editorconfig
для определения стиля кодирования. Visual Studio понимает этот файл и предоставляет быстрые исправления, чтобы ваш код соответствовал стилю кодирования. Однако легко пропустить некоторые предупреждения и выложить код, не соответствующий стилю.dotnet format
позволяет форматировать файлы решения согласно стилю кодирования. Но он также может проверить, соответствует ли ваш код стилю кодирования, определенному в файле .editorconfig
. Вы можете использовать параметр --check
, чтобы инструмент не перезаписывал файлы, а только возвращал ненулевой код результата, когда файл не соответствует стилю кодирования.dotnet tool update -g dotnet-formatКроме того, можно проверить стиль кодирования в конвейере CI. Например, в Azure Pipeline вы можете использовать следующий код:
dotnet format --check
stages:Если файл не соответствует стилю кодирования, будут выведены детали ошибки, и сборка завершится неудачей.
- stage: build
jobs:
- job: "lint"
pool:
vmImage: 'ubuntu-latest'
# Устанавливаем последнюю версию .NET Core SDK
- task: UseDotNet@2
inputs:
packageType: 'sdk'
version: '3.1.x'
# Устанавливаем dotnet format
- task: DotNetCoreCLI@2
displayName: 'Install dotnet format'
inputs:
command: 'custom'
custom: 'tool'
arguments: 'update -g dotnet-format'
# Выполняем dotnet format --dry-run --check
# По умолчанию задача сравнивает результат с 0
- task: DotNetCoreCLI@2
displayName: 'Lint dotnet'
inputs:
command: 'custom'
custom: 'format'
arguments: '--check --verbosity diagnostic'
Другой вариант – использовать
script
вместо DotNetCoreCLI@2
:stages:Источник: https://www.meziantou.net/enforce-dotnet-code-style-in-ci-with-dotnet-format.htm
- stage: build
jobs:
- job: "lint"
pool:
vmImage: 'ubuntu-latest'
- task: UseDotNet@2
inputs:
packageType: 'sdk'
version: '3.1.x'
- script: 'dotnet tool update -g dotnet-format && dotnet format --check --verbosity diagnostic'
displayName: 'Lint dotnet'
This media is not supported in your browser
VIEW IN TELEGRAM
День пятьсот восемьдесят восьмой. #TipsAndTricks
Повышаем продуктивность в Visual Studio.
35. Расширяем и Сужаем Выделение
Вы можете использовать горячие клавиши, чтобы расширить или сузить область выделенного кода в Visual Studio. Поместите курсор на любой элемент и нажмите
Если вы хотите выделить сразу весь родительский блок кода (весь блок
Источник: https://www.youtube.com/watch?v=uAHr_-hh7LI
Повышаем продуктивность в Visual Studio.
35. Расширяем и Сужаем Выделение
Вы можете использовать горячие клавиши, чтобы расширить или сузить область выделенного кода в Visual Studio. Поместите курсор на любой элемент и нажмите
Shift+Alt++
. С каждым нажатием будет выделяться элемент, окружающий текущее выделение. Можно сужать область выделения с помощью горячих клавиш Shift+Alt+-
.Если вы хотите выделить сразу весь родительский блок кода (весь блок
if
|using
|try
и т.п.), вы можете использовать сочетание клавиш Shift+Alt+]
. При этом сузить выделение можно так же через Shift+Alt+-
, в этом случае с шагом на весь родительский блок.Источник: https://www.youtube.com/watch?v=uAHr_-hh7LI
День пятьсот восемьдесят девятый. #Оффтоп
Последний Язык Программирования
Люблю я сказки дядюшки Боба. Вот вам очередная (довольно старая, но всё-таки).
За последние 50 лет мы увидели множество компьютерных языков: процедурные, структурированные, объектно-ориентированные, языки стека, языки логики, графические языки, и даже языки, основанные на игре в жизнь. Мы видели так много разных языков и разных типов языков, что становится интересно: видели ли мы их все?
Есть ли еще типы языков, которых мы не видели? Или мы полностью изучили языковое пространство? И если да, то не пора ли нам сократить весь этот зоопарк языков до небольшого количества - возможно, даже до одного?
Другие отрасли сделали это, количество нотаций сократилось с десятков до одной. Электроника, химия, биология, математика и т.д. - все используют единую систему единиц измерения. И выгода, которую они получили от этого, была значительной! Возможно, нам пора последовать их примеру.
Если бы мы выбрали язык, каким бы он был? Какие функции у него были бы? Какого синтаксиса он будет придерживаться? Каким парадигмам он будет соответствовать?
https://www.youtube.com/watch?v=P2yr-3F6PQo
Последний Язык Программирования
Люблю я сказки дядюшки Боба. Вот вам очередная (довольно старая, но всё-таки).
За последние 50 лет мы увидели множество компьютерных языков: процедурные, структурированные, объектно-ориентированные, языки стека, языки логики, графические языки, и даже языки, основанные на игре в жизнь. Мы видели так много разных языков и разных типов языков, что становится интересно: видели ли мы их все?
Есть ли еще типы языков, которых мы не видели? Или мы полностью изучили языковое пространство? И если да, то не пора ли нам сократить весь этот зоопарк языков до небольшого количества - возможно, даже до одного?
Другие отрасли сделали это, количество нотаций сократилось с десятков до одной. Электроника, химия, биология, математика и т.д. - все используют единую систему единиц измерения. И выгода, которую они получили от этого, была значительной! Возможно, нам пора последовать их примеру.
Если бы мы выбрали язык, каким бы он был? Какие функции у него были бы? Какого синтаксиса он будет придерживаться? Каким парадигмам он будет соответствовать?
https://www.youtube.com/watch?v=P2yr-3F6PQo
YouTube
The Last Programming Language
This is the keynote Uncle Bob gave remotely at ACCU 2011.
To see more about Clean Coders: https://cleancoders.com/
Over the last 50 years we've seen a lot of computer languages, from procedural languages, to structured languages, to OO languages, stack…
To see more about Clean Coders: https://cleancoders.com/
Over the last 50 years we've seen a lot of computer languages, from procedural languages, to structured languages, to OO languages, stack…
День пятьсот девяностый. #Оффтоп
Будущее Паролей – Отсутствие Паролей
Пароли ненадёжны. Несмотря на то, что растёт общая грамотность пользователей, а также всё более распространяются менеджеры паролей, качество пароля зависит от как от сложности и уникальности пароля, так и от безопасности самого приложения или веб-сайта.
Сложно добиться надёжности пароля. Правила заставляют пользователей менять свои простые пароли, но в лучшем случае они меняются с password123 на password123!. Большинство наших родителей (да и не только старшее поколение, чего уж там) создают наиболее простые пароли, потому что их легче запомнить. А то и вообще хранят их на видном месте.
Вы можете установить надёжный пароль, но сложно добиться его уникальности. И даже если вы сознательный интернет-гражданин и генерируете уникальный длинный пароль для каждой создаваемой учетной записи, если сайт будет взломан, не имеет значения, насколько надёжен ваш пароль, если он хранится в виде открытого текста.
Двухфакторная аутентификация стала новой нормой: многие продукты теперь её используют, а компании требуют от своих сотрудников использовать её для своей электронной почты и других корпоративных услуг.
Как работает аутентификация без пароля?
Скорее всего, вы уже сталкивались с приложением или сервисом, использующим аутентификацию без пароля. Самая популярная форма – письмо по электронной почте с магической ссылкой, содержащей специальный токен, срок действия которого истекает через несколько минут. Нажав на неё, вы зайдёте в сервис как аутентифицированный пользователь. Ещё один вариант - SMS код (аналог одноразового пароля).
Безопасна ли аутентификация без пароля?
На самом деле аутентификация без пароля - это не что иное, как расширенная модель сброса пароля. Подход тот же: вместо сброса существующего пароля, пароль удаляется совсем, а вместо ссылки для сброса пароля используется одноразовая ссылка для входа.
Можно подумать, что в этом случае вектор атаки перейдёт на электронную почту пользователя. Но ведь если кто-то получит доступ к почте, они так же смогут сбросить пароль.
Мы постоянно слышим о новых и новых утечках данных. В будущем, в котором пароли будут исключены из уравнения, возможно, хакеры сосредоточат свои усилия не на попытках взлома баз данных в поисках открытых или слабо захешированных паролей, а на чём-то другом.
Очевидно, что полное отсутствие пароля никогда не будет возможным. Например, для вашей учетной записи электронной почты всегда будет нужен пароль. Но лучше запомнить только один надежный пароль для своей электронной почты, чем повторно использовать один надежный пароль для всего или слабые пароли, которые легко взломать или угадать.
Итого
Пока аутентификация без пароля мало используется в личных проектах из-за сравнительно больших затрат. Но, в конце концов, похоже, что переход на аутентификацию без пароля везде, где это возможно, неизбежен.
Что скажете? Высказывайте свои соображения в нашем чате.
Источник: https://ilikekillnerds.com/2020/09/the-future-of-passwords-is-no-passwords/
Будущее Паролей – Отсутствие Паролей
Пароли ненадёжны. Несмотря на то, что растёт общая грамотность пользователей, а также всё более распространяются менеджеры паролей, качество пароля зависит от как от сложности и уникальности пароля, так и от безопасности самого приложения или веб-сайта.
Сложно добиться надёжности пароля. Правила заставляют пользователей менять свои простые пароли, но в лучшем случае они меняются с password123 на password123!. Большинство наших родителей (да и не только старшее поколение, чего уж там) создают наиболее простые пароли, потому что их легче запомнить. А то и вообще хранят их на видном месте.
Вы можете установить надёжный пароль, но сложно добиться его уникальности. И даже если вы сознательный интернет-гражданин и генерируете уникальный длинный пароль для каждой создаваемой учетной записи, если сайт будет взломан, не имеет значения, насколько надёжен ваш пароль, если он хранится в виде открытого текста.
Двухфакторная аутентификация стала новой нормой: многие продукты теперь её используют, а компании требуют от своих сотрудников использовать её для своей электронной почты и других корпоративных услуг.
Как работает аутентификация без пароля?
Скорее всего, вы уже сталкивались с приложением или сервисом, использующим аутентификацию без пароля. Самая популярная форма – письмо по электронной почте с магической ссылкой, содержащей специальный токен, срок действия которого истекает через несколько минут. Нажав на неё, вы зайдёте в сервис как аутентифицированный пользователь. Ещё один вариант - SMS код (аналог одноразового пароля).
Безопасна ли аутентификация без пароля?
На самом деле аутентификация без пароля - это не что иное, как расширенная модель сброса пароля. Подход тот же: вместо сброса существующего пароля, пароль удаляется совсем, а вместо ссылки для сброса пароля используется одноразовая ссылка для входа.
Можно подумать, что в этом случае вектор атаки перейдёт на электронную почту пользователя. Но ведь если кто-то получит доступ к почте, они так же смогут сбросить пароль.
Мы постоянно слышим о новых и новых утечках данных. В будущем, в котором пароли будут исключены из уравнения, возможно, хакеры сосредоточат свои усилия не на попытках взлома баз данных в поисках открытых или слабо захешированных паролей, а на чём-то другом.
Очевидно, что полное отсутствие пароля никогда не будет возможным. Например, для вашей учетной записи электронной почты всегда будет нужен пароль. Но лучше запомнить только один надежный пароль для своей электронной почты, чем повторно использовать один надежный пароль для всего или слабые пароли, которые легко взломать или угадать.
Итого
Пока аутентификация без пароля мало используется в личных проектах из-за сравнительно больших затрат. Но, в конце концов, похоже, что переход на аутентификацию без пароля везде, где это возможно, неизбежен.
Что скажете? Высказывайте свои соображения в нашем чате.
Источник: https://ilikekillnerds.com/2020/09/the-future-of-passwords-is-no-passwords/
День пятьсот девяносто первый. #Оффтоп
С профессиональным праздником всех читателей! Сегодняшняя тема как раз под повод.
7 Привычек Эффективных Программистов
Карьера программиста обычно довольно долгая. Как не допустить профессионального выгорания? Помогут некоторые привычки, которые нужно у себя выработать.
1. Держите Себя в Форме
Программирование – это физически сложный труд. Многие представляют программистов расслабленно развалившимися в креслах, тыкающими по кнопкам. Но этим нельзя заниматься долго. Спина затекает, тело принимает форму стула, глаза пересыхают от долгого смотрения в экран, кожа становится бледной от недостатка солнечных лучей. Поэтому критически важны не только правильная посадка, но и регулярные физические упражнения, а также хороший сон. Делайте перерывы каждые полчаса, пейте побольше жидкости, выходите погулять в обеденный перерыв.
2. Главное - продукт
Часто можно наблюдать картину, как программист выполняет 80% задачи, а потом закапывается в дебри отладки, пытаясь исправить мелкий назойливый баг или довести до идеала определённый кусок кода или UI. Это в природе программистов – пытаться решить проблему. Вариант этого – чрезмерное увлечение рефакторингом, пытаясь довести код до совершенства. Но каким бы соблазнительным это ни казалось, нельзя упускать из виду полную картину. Ваша главная задача – доставить продукт.
Также многие тратят кучу времени на тонкую настройку IDE, конфигурацию горячих клавиш и подсветки синтаксиса, установку кучи плагинов и мелких программ, помогающих в работе. С этим есть одна проблема: если вдруг вам придётся перейти на другую машину, там всё будет настроено по-другому, и ваша продуктивность резко упадёт.
3. KISS
Сохраняйте код простым. В программировании довольно много высокомерных людей. Они считают, что чем «умнее» будет их код, чем меньше людей будет понимать, что они сделали, тем лучше. Но на самом деле, всё наоборот. Ваши коллеги, или даже вы спустя несколько месяцев должны, взглянув на код, легко понять, что он делает.
4. Научитесь «Ловить Волну»
Под «поймать волну» здесь имеется в виду ваше состояние, в котором вы быстро пишете код, решаете любые трудности, теряете счёт времени и даже не замечаете, как выполняете задачу до конца. Это может быть 2-3 часа, когда вас никто не отрывает от работы и ничто не мешает. При написании программы вам нужно держать в голове алгоритмы и абстракции, которые нужно реализовать, а если вас постоянно отвлекают, всё рушится, и приходится строить их снова. Сообщите людям, окружающим вас, что вам нужно время поработать, уберите все отвлекающие предметы и уделите время только работе.
5. Постоянно Прогрессируйте
Постоянно изучайте и используйте что-то новое. В работе вы обычно используете ограниченное число технологий. В этом можно «застрять». Вы можете быть продуктивным в этой области несколько месяцев или лет, но потом обнаружить, что все вокруг ушли далеко вперёд, а вы отстали.
6. Сотрудничайте
Многие представляют себе профессию программиста, как одинокого хакера, проводящего время наедине с самим собой. Но это не очень эффективно. Часто программисты уединяются с задачей, тратят уйму времени на её решение, когда можно спросить совета коллег и получить ответ сразу. Это не значит, что нужно доставать их при каждом затруднении. Отведите себе разумное время и попробуйте сами решить проблему. Но если это не удастся, не тратьте время дальше, спросите совета. Чаще всего программирование – командный спорт.
7. Программирование – для Одиночек
Это может звучать, как противоречие к предыдущему пункту. Но на самом деле, программист, наверное, наиболее одинокая профессия в мире. Вы не будете на постоянной основе общаться с десятками людей. Большинство времени программист проводит наедине со своими мыслями, читая документацию, отлаживая код или конструируя функционал. Нужно просто привыкнуть к этому.
Ещё раз, с праздником!
Источник: https://www.youtube.com/watch?v=W8ykZNSLDqE
С профессиональным праздником всех читателей! Сегодняшняя тема как раз под повод.
7 Привычек Эффективных Программистов
Карьера программиста обычно довольно долгая. Как не допустить профессионального выгорания? Помогут некоторые привычки, которые нужно у себя выработать.
1. Держите Себя в Форме
Программирование – это физически сложный труд. Многие представляют программистов расслабленно развалившимися в креслах, тыкающими по кнопкам. Но этим нельзя заниматься долго. Спина затекает, тело принимает форму стула, глаза пересыхают от долгого смотрения в экран, кожа становится бледной от недостатка солнечных лучей. Поэтому критически важны не только правильная посадка, но и регулярные физические упражнения, а также хороший сон. Делайте перерывы каждые полчаса, пейте побольше жидкости, выходите погулять в обеденный перерыв.
2. Главное - продукт
Часто можно наблюдать картину, как программист выполняет 80% задачи, а потом закапывается в дебри отладки, пытаясь исправить мелкий назойливый баг или довести до идеала определённый кусок кода или UI. Это в природе программистов – пытаться решить проблему. Вариант этого – чрезмерное увлечение рефакторингом, пытаясь довести код до совершенства. Но каким бы соблазнительным это ни казалось, нельзя упускать из виду полную картину. Ваша главная задача – доставить продукт.
Также многие тратят кучу времени на тонкую настройку IDE, конфигурацию горячих клавиш и подсветки синтаксиса, установку кучи плагинов и мелких программ, помогающих в работе. С этим есть одна проблема: если вдруг вам придётся перейти на другую машину, там всё будет настроено по-другому, и ваша продуктивность резко упадёт.
3. KISS
Сохраняйте код простым. В программировании довольно много высокомерных людей. Они считают, что чем «умнее» будет их код, чем меньше людей будет понимать, что они сделали, тем лучше. Но на самом деле, всё наоборот. Ваши коллеги, или даже вы спустя несколько месяцев должны, взглянув на код, легко понять, что он делает.
4. Научитесь «Ловить Волну»
Под «поймать волну» здесь имеется в виду ваше состояние, в котором вы быстро пишете код, решаете любые трудности, теряете счёт времени и даже не замечаете, как выполняете задачу до конца. Это может быть 2-3 часа, когда вас никто не отрывает от работы и ничто не мешает. При написании программы вам нужно держать в голове алгоритмы и абстракции, которые нужно реализовать, а если вас постоянно отвлекают, всё рушится, и приходится строить их снова. Сообщите людям, окружающим вас, что вам нужно время поработать, уберите все отвлекающие предметы и уделите время только работе.
5. Постоянно Прогрессируйте
Постоянно изучайте и используйте что-то новое. В работе вы обычно используете ограниченное число технологий. В этом можно «застрять». Вы можете быть продуктивным в этой области несколько месяцев или лет, но потом обнаружить, что все вокруг ушли далеко вперёд, а вы отстали.
6. Сотрудничайте
Многие представляют себе профессию программиста, как одинокого хакера, проводящего время наедине с самим собой. Но это не очень эффективно. Часто программисты уединяются с задачей, тратят уйму времени на её решение, когда можно спросить совета коллег и получить ответ сразу. Это не значит, что нужно доставать их при каждом затруднении. Отведите себе разумное время и попробуйте сами решить проблему. Но если это не удастся, не тратьте время дальше, спросите совета. Чаще всего программирование – командный спорт.
7. Программирование – для Одиночек
Это может звучать, как противоречие к предыдущему пункту. Но на самом деле, программист, наверное, наиболее одинокая профессия в мире. Вы не будете на постоянной основе общаться с десятками людей. Большинство времени программист проводит наедине со своими мыслями, читая документацию, отлаживая код или конструируя функционал. Нужно просто привыкнуть к этому.
Ещё раз, с праздником!
Источник: https://www.youtube.com/watch?v=W8ykZNSLDqE
День пятьсот девяносто второй. #ЗаметкиНаПолях
Индексы и Диапазоны в C#8
Я уже писал о новых классах
Range
Это структура с двумя важными свойствами:
Непосредственно в
Класс
- Значение индекса - неотрицательное целое число (свойство
- Значение может быть с начала или с конца последовательности (определяется в свойстве
Мы можем создать экземпляр
Источник: https://khalidabuhakmeh.com/use-range-and-index-in-csharp-8
Индексы и Диапазоны в C#8
Я уже писал о новых классах
Index
и Range
в C#8. Здесь мы рассмотрим их подробнее.Range
Это структура с двумя важными свойствами:
Start
и End
типа Index
(о нём позже), где Start
– это индекс начального элемента диапазона, а End
– индекс конечного (не включая конечный элемент): public readonly struct Range : IEquatable<Range> {Использовать
public Index Start { get; }
public Index End { get; }
public Range(Index start, Index end) {
Start = start;
End = end;
}
…
}
Range
можно как через обычный конструкторvar oldSchool = new Range(1,4);так и через новый оператор диапазона, который можно представить так:
System.Range operator ..(Index start = 0, Index end = ^0);Помните, что
var range = 1..4;
Range
- это тип, представляющий только начало и конец. Он не содержит элементов внутри диапазона, пока мы не применим его к коллекции.Непосредственно в
Range
мы можем лишь получить границы:Console.WriteLine($"диапазон с {range.Start}-го по {range.End}-й элемент");Можно спутать выражение
1..4
, как получение целых чисел от 1 до 3 (4 не включается), но на самом деле это делается так: var numbers = Enumerable.Range(0, 10).ToArray();При этом синтаксис оператора .. допускает отсутствие одного или обоих аргументов. Тогда вместо отсутствующего аргумента будет выступать соответственно начало или конец последовательности:
var result = numbers[1..4];
//от начала до элемента с индексом 3Класс Index
var slice = numbers[..3];
Класс
Index
используется для определения начального или конечного значения диапазона. Давайте посмотрим на конструктор класса:public Index(int value, bool fromEnd = false) {Отметим две важные характеристики:
if (value < 0) {
ThrowHelper.ThrowValueArgumentOutOfRange_NeedNonNegNumException();
}
if (fromEnd)
_value = ~value;
else
_value = value;
}
- Значение индекса - неотрицательное целое число (свойство
Value
).- Значение может быть с начала или с конца последовательности (определяется в свойстве
IsFromEnd
).Мы можем создать экземпляр
Index
как через обычный конструктор:var oldSchool = new Index(1, fromEnd: true)так и используя унарный оператор
^
, который можно представить следующим образом:System.Index operator ^(int fromEnd);То есть получить последний элемент коллекции можно так:
var last = numbers[^1];Замечание: нельзя использовать индекс
^0
. Это приведёт к исключению IndexOutOfRangeException
. Однако, мы можем использовать ^0
в диапазоне, т.к. последний элемент диапазона не включается:var slice = numbers[2..^0];Что будет равносильно
var slice = numbers[2..];Окончание следует…
Источник: https://khalidabuhakmeh.com/use-range-and-index-in-csharp-8
День пятьсот девяносто третий. #ЗаметкиНаПолях
Индексы и Диапазоны в C#8. Окончание
Начало
Ограничения
Существуют ограничения для классов Range и Index, которые лучше всего описаны в документации Microsoft:
"Следующие типы .NET поддерживают как индексы, так и диапазоны: String, Span<T> и ReadOnlySpan<T>. List<T> поддерживает индексы, но не поддерживает диапазоны."
Непоследовательная поддержка
При создании своего типа, поддерживающего
1. Для Range:
- чтобы тип был счётным,
- имел доступный член с именем
- имел индексатор с единственным параметром типа
2. Для Index:
- чтобы тип был счётным,
- имел доступный индексатор с единственным параметром типа
- имел индексатор с единственным параметром типа
Недостатки
Хотя новые классы
1. Многие диапазоны не связаны с целыми числами. Очень неплохо было бы видеть в будущем, например, обобщённые индексы и диапазоны, например, для даты, времени, букв и т.п.:
3. Очень не хватает ошибок времени компиляции при использовании
Итого
Типы
Источник: https://khalidabuhakmeh.com/use-range-and-index-in-csharp-8
Индексы и Диапазоны в C#8. Окончание
Начало
Ограничения
Существуют ограничения для классов Range и Index, которые лучше всего описаны в документации Microsoft:
"Следующие типы .NET поддерживают как индексы, так и диапазоны: String, Span<T> и ReadOnlySpan<T>. List<T> поддерживает индексы, но не поддерживает диапазоны."
Непоследовательная поддержка
Index
и Range
может расстраивать. Чтобы работать с новым синтаксисом, может потребоваться вызов ToArray
, то есть ненужное выделение памяти.При создании своего типа, поддерживающего
Range
и Index
, необходимо:1. Для Range:
- чтобы тип был счётным,
- имел доступный член с именем
Slice
с двумя параметрами типа int
,- имел индексатор с единственным параметром типа
Range
или остальными необязательными параметрами.2. Для Index:
- чтобы тип был счётным,
- имел доступный индексатор с единственным параметром типа
int
,- имел индексатор с единственным параметром типа
Index
или остальными необязательными параметрами.Недостатки
Хотя новые классы
Range
и Index
являются долгожданным функционалом в C#, они всё ещё кажутся ограниченными:1. Многие диапазоны не связаны с целыми числами. Очень неплохо было бы видеть в будущем, например, обобщённые индексы и диапазоны, например, для даты, времени, букв и т.п.:
var year = new DateTime(2020, 1,1)..new DateTime(2020, 12, 31);2.
var characters = a..z;
List<T>
, вероятно, является наиболее широко используемым обобщённым типом данных в .NET, и отсутствие поддержки Range
кажется странным. 3. Очень не хватает ошибок времени компиляции при использовании
Range
. Например, следующий код:var wrong = numbers[1..0];скомпилируется, но вызовет ошибку времени выполнения. Ничто не запрещает создать диапазон
1..0
, и некоторые пользовательские типы, реализующие работу с диапазонами, возможно даже смогут его обработать. Однако даже перечисленные выше типы, работающие с диапазонами «из коробки» не смогут этого сделать. Хотелось бы, чтобы компилятор знал об этом.Итого
Типы
Range
и Index
делают кодовую базу более чистой, но в настоящее время они ограничены диапазонами на основе целых чисел. Они мощные, но их непоследовательность может ввести в заблуждение некоторых разработчиков. Различные реализации могут также привести к тому, что разработчики, сами того не ожидая, будут использовать лишнюю память. Таким образом, это всё ещё относительно новый функционал, и стоит подождать обновлений языка, которые сделают его поддержку более широкой и последовательной.Источник: https://khalidabuhakmeh.com/use-range-and-index-in-csharp-8
👍1
День пятьсот девяносто четвёртый. #TipsAndTricks
Окно Disassembly для Отладки Оптимизированного Кода
В борьбе за производительность службы или приложения .NET, вы можете пользоваться преимуществами оптимизации JIT-компилятора. Однако отладка оптимизированного кода может стать проблемой.
Что происходит, когда код оптимизируется?
Когда JIT-компилятор оптимизирует код, он может реорганизовать инструкции с целью создания более быстрого и эффективного скомпилированного кода. После этих изменений инструменты отладки, такие как Visual Studio или WinDbg, не всегда могут сразу идентифицировать исходный код, соответствующий набору инструкций.
Оптимизация компилятора также может влиять на локальные переменные, удаляя или перемещая их. Строки кода меняют порядок, когда при оптимизации объединяются блоки кода. Также возможно, что изменятся имена функций изменятся в стеке вызовов, если оптимизатор объединяет функции.
При отладке оптимизированного кода вы можете столкнуться со следующими проблемами:
- Точки останова не всегда могут быть привязаны к соответствующему местоположению источника.
- Исполнение по шагам не всегда может вести в нужное место.
- Некоторые переменные могут быть недоступны для оценки.
Таким образом, отладка оптимизированного кода может быть сложной, даже если у вас есть прямой доступ к исходному коду.
Просмотр дизассемблированного кода
В Visual Studio есть окно Disassembly, которое даёт вам возможность проверять каждую деталь каждой оптимизированной инструкции. В окне Disassembly отображается код сборки, который непосредственно соответствует инструкциям, созданным компилятором. Если вы отлаживаете управляемый код, то инструкции точно соответствуют коду, созданному JIT-компилятором.
Чтобы открыть окно Disassembly во время отладки кода или дампа, выберите Debug > Windows > Disassembly (Ctrl+Alt+D).
Поиск источника NullReferenceException
Необработанные NullReferenceException - одна из наиболее частых причин сбоев в приложениях. Они могут неожиданно возникать в продакшене по разным причинам, включая отсутствие данных или неправильные настройки конфигурации. Если вы записали и открыли дамп в Visual Studio, вы можете быстро перейти к нужному потоку, стеку вызовов и даже к строке кода.
Однако в оптимизированном дампе (где локальные переменные обычно недоступны) это может быть очень сложно. В этом случае окно Disassembly даст нам гораздо более чёткое указание на проблемные объекты.
На картинке ниже показано окно Disassembly с аварийным дампом, собранным из управляемого процесса. Здесь выделены инструкции ассемблера и исходный код, что помогает определить, что
Источник: https://devblogs.microsoft.com/visualstudio/disassembly-improvements-for-optimized-debugging/
Окно Disassembly для Отладки Оптимизированного Кода
В борьбе за производительность службы или приложения .NET, вы можете пользоваться преимуществами оптимизации JIT-компилятора. Однако отладка оптимизированного кода может стать проблемой.
Что происходит, когда код оптимизируется?
Когда JIT-компилятор оптимизирует код, он может реорганизовать инструкции с целью создания более быстрого и эффективного скомпилированного кода. После этих изменений инструменты отладки, такие как Visual Studio или WinDbg, не всегда могут сразу идентифицировать исходный код, соответствующий набору инструкций.
Оптимизация компилятора также может влиять на локальные переменные, удаляя или перемещая их. Строки кода меняют порядок, когда при оптимизации объединяются блоки кода. Также возможно, что изменятся имена функций изменятся в стеке вызовов, если оптимизатор объединяет функции.
При отладке оптимизированного кода вы можете столкнуться со следующими проблемами:
- Точки останова не всегда могут быть привязаны к соответствующему местоположению источника.
- Исполнение по шагам не всегда может вести в нужное место.
- Некоторые переменные могут быть недоступны для оценки.
Таким образом, отладка оптимизированного кода может быть сложной, даже если у вас есть прямой доступ к исходному коду.
Просмотр дизассемблированного кода
В Visual Studio есть окно Disassembly, которое даёт вам возможность проверять каждую деталь каждой оптимизированной инструкции. В окне Disassembly отображается код сборки, который непосредственно соответствует инструкциям, созданным компилятором. Если вы отлаживаете управляемый код, то инструкции точно соответствуют коду, созданному JIT-компилятором.
Чтобы открыть окно Disassembly во время отладки кода или дампа, выберите Debug > Windows > Disassembly (Ctrl+Alt+D).
Поиск источника NullReferenceException
Необработанные NullReferenceException - одна из наиболее частых причин сбоев в приложениях. Они могут неожиданно возникать в продакшене по разным причинам, включая отсутствие данных или неправильные настройки конфигурации. Если вы записали и открыли дамп в Visual Studio, вы можете быстро перейти к нужному потоку, стеку вызовов и даже к строке кода.
Однако в оптимизированном дампе (где локальные переменные обычно недоступны) это может быть очень сложно. В этом случае окно Disassembly даст нам гораздо более чёткое указание на проблемные объекты.
На картинке ниже показано окно Disassembly с аварийным дампом, собранным из управляемого процесса. Здесь выделены инструкции ассемблера и исходный код, что помогает определить, что
[rbp-8]
- место, где определён объект hnd1
, и свойство FileHandler
действительно является источником наблюдаемого сбоя.Источник: https://devblogs.microsoft.com/visualstudio/disassembly-improvements-for-optimized-debugging/
День пятьсот девяносто пятый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
59. Только Код Скажет Правду
Конечная семантика программы определяется исходным кодом. Если он только в двоичной форме, его будет трудно прочитать. Но, если это ваша программа, любая коммерческая разработка ПО, проект с открытым исходным кодом или код на динамически интерпретируемом языке, тогда исходный код программы доступен. Когда вы смотрите на исходный код, смысл программы должен быть очевиден. Чтобы узнать, что делает программа, исходный код – вот всё, в чём вы можете быть уверены. Даже самый точный документ с ТЗ не говорит всей правды: он содержит только высокоуровневые намерения, а не подробное описание того, что делает программа. Проектный документ может отражать запланированный дизайн, но в нём не будет необходимых деталей реализации. Кроме того, такие документы могут устаревать и больше не отражать текущую реализацию. Также они могут быть утеряны … или их вообще никогда не писали. Исходный код – единственное, что у вас осталось.
Имея это в виду, спросите себя, насколько чётко ваш код сообщает вам или любому другому программисту, что он делает.
Вы можете подумать, что комментарии расскажут всё, что вам нужно знать. Но имейте в виду, что комментарии - это не исполняемый код. Они могут быть такими же ошибочными, как и другие формы документации. Существует убеждение, что комментарии - это всегда хорошо, поэтому некоторые программисты постоянно пишут огромное количество комментариев, даже переформулируя и объясняя мелочи, уже очевидные из кода. Это неправильный способ объяснения работы вашего кода.
Если вашему коду нужны комментарии, подумайте о его рефакторинге, чтобы этого не требовалось. Длинные комментарии могут загромождать пространство на экране и даже могут автоматически скрываться вашей IDE. Если вам нужно объяснить изменение, сделайте это в комментарии коммита системы контроля версий, а не в коде.
Что вы можете сделать, чтобы ваш код действительно выражал ваши намерения как можно яснее? Стремитесь использовать хорошие имена. Структурируйте свой код с учетом целостной функциональности (одна задача – один класс, одна функция – один метод), что также упрощает именование. Разделите свой код для достижения ортогональности (повторного использования). Напишите автоматизированные тесты, объясняющие предполагаемое поведение, и проверьте интерфейсы. Безжалостно проводите рефакторинг, когда вы находите более простое решение. Сделайте свой код максимально простым для чтения и понимания.
Относитесь к своему коду как к любому другому произведению, например к стихотворению, эссе, публичному блогу или важному электронному письму. Тщательно обдумывайте то, что вы пишете, чтобы оно делало то, что должно, и как можно более чётко выражало то, что делает. Чтобы произведение продолжало выражать ваши намерения даже вашим потомкам. Помните, что полезный код используется намного дольше, чем изначально предполагалось. Обслуживающие его программисты будут вам благодарны.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Peter Sommerlad.
97 Вещей, Которые Должен Знать Каждый Программист
59. Только Код Скажет Правду
Конечная семантика программы определяется исходным кодом. Если он только в двоичной форме, его будет трудно прочитать. Но, если это ваша программа, любая коммерческая разработка ПО, проект с открытым исходным кодом или код на динамически интерпретируемом языке, тогда исходный код программы доступен. Когда вы смотрите на исходный код, смысл программы должен быть очевиден. Чтобы узнать, что делает программа, исходный код – вот всё, в чём вы можете быть уверены. Даже самый точный документ с ТЗ не говорит всей правды: он содержит только высокоуровневые намерения, а не подробное описание того, что делает программа. Проектный документ может отражать запланированный дизайн, но в нём не будет необходимых деталей реализации. Кроме того, такие документы могут устаревать и больше не отражать текущую реализацию. Также они могут быть утеряны … или их вообще никогда не писали. Исходный код – единственное, что у вас осталось.
Имея это в виду, спросите себя, насколько чётко ваш код сообщает вам или любому другому программисту, что он делает.
Вы можете подумать, что комментарии расскажут всё, что вам нужно знать. Но имейте в виду, что комментарии - это не исполняемый код. Они могут быть такими же ошибочными, как и другие формы документации. Существует убеждение, что комментарии - это всегда хорошо, поэтому некоторые программисты постоянно пишут огромное количество комментариев, даже переформулируя и объясняя мелочи, уже очевидные из кода. Это неправильный способ объяснения работы вашего кода.
Если вашему коду нужны комментарии, подумайте о его рефакторинге, чтобы этого не требовалось. Длинные комментарии могут загромождать пространство на экране и даже могут автоматически скрываться вашей IDE. Если вам нужно объяснить изменение, сделайте это в комментарии коммита системы контроля версий, а не в коде.
Что вы можете сделать, чтобы ваш код действительно выражал ваши намерения как можно яснее? Стремитесь использовать хорошие имена. Структурируйте свой код с учетом целостной функциональности (одна задача – один класс, одна функция – один метод), что также упрощает именование. Разделите свой код для достижения ортогональности (повторного использования). Напишите автоматизированные тесты, объясняющие предполагаемое поведение, и проверьте интерфейсы. Безжалостно проводите рефакторинг, когда вы находите более простое решение. Сделайте свой код максимально простым для чтения и понимания.
Относитесь к своему коду как к любому другому произведению, например к стихотворению, эссе, публичному блогу или важному электронному письму. Тщательно обдумывайте то, что вы пишете, чтобы оно делало то, что должно, и как можно более чётко выражало то, что делает. Чтобы произведение продолжало выражать ваши намерения даже вашим потомкам. Помните, что полезный код используется намного дольше, чем изначально предполагалось. Обслуживающие его программисты будут вам благодарны.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Peter Sommerlad.
День пятьсот девяносто шестой. #Оффтоп #Курсы
Дни виртуального обучения Microsoft
Вчера имел удовольствие посетить онлайн урок по основам Azure от Microsoft. Сегодня будет вторая серия. Конкретно эти уроки – самый начальный уровень знаний об Azure, поэтому я не стал о них писать до того, как попробовал на себе. Однако оказалось, что от них есть польза. Помимо очень подробного (на русском языке) рассказа об облачных вычислениях и показа на практике возможностей Azure, в конце курса (то есть сегодня) даётся сертификат, который позволит бесплатно пройти экзамен AZ-900. Да, экзамен по самым основам, и особо его сдача ни о чём не говорит, но халява же)))
На этот курс вам уже не записаться, но его повторят в октябре (19 и 20) и, насколько я понял, будут повторять ежемесячно. Поэтому все желающие могут регистрироваться уже сейчас. Единственный минус - посреди рабочего дня.
Кроме того, таких курсов у Microsoft целая серия: по Azure, Microsoft 365 и Dynamics 365. Называются они «Дни виртуального обучения». Вот здесь полное расписание. В ближайшее время обещают выложить расписание на октябрь.
Я, например, записался ещё на один курс «Modernizing Web Applications and Data», который пройдёт 29 и 30 сентября. Там расскажут о том, как перенести веб-приложения и базы данных на платформу Azure. Этот курс уже на английском.
Дни виртуального обучения Microsoft
Вчера имел удовольствие посетить онлайн урок по основам Azure от Microsoft. Сегодня будет вторая серия. Конкретно эти уроки – самый начальный уровень знаний об Azure, поэтому я не стал о них писать до того, как попробовал на себе. Однако оказалось, что от них есть польза. Помимо очень подробного (на русском языке) рассказа об облачных вычислениях и показа на практике возможностей Azure, в конце курса (то есть сегодня) даётся сертификат, который позволит бесплатно пройти экзамен AZ-900. Да, экзамен по самым основам, и особо его сдача ни о чём не говорит, но халява же)))
На этот курс вам уже не записаться, но его повторят в октябре (19 и 20) и, насколько я понял, будут повторять ежемесячно. Поэтому все желающие могут регистрироваться уже сейчас. Единственный минус - посреди рабочего дня.
Кроме того, таких курсов у Microsoft целая серия: по Azure, Microsoft 365 и Dynamics 365. Называются они «Дни виртуального обучения». Вот здесь полное расписание. В ближайшее время обещают выложить расписание на октябрь.
Я, например, записался ещё на один курс «Modernizing Web Applications and Data», который пройдёт 29 и 30 сентября. Там расскажут о том, как перенести веб-приложения и базы данных на платформу Azure. Этот курс уже на английском.
День пятьсот девяносто седьмой. #MoreEffectiveCSharp
17. Избегайте Возврата Ссылок на Внутренний Класс
Вы можете думать, что свойство только для чтения доступно только для чтения и вызывающие объекты не могут его изменять. К сожалению, так получается не всегда. Если свойство возвращает ссылочный тип, вызывающий код может получить доступ к любому общедоступному члену этого объекта, включая те, которые изменяют его состояние. Например:
Добро пожаловать в чудесный мир ссылочных типов. Любой член, возвращающий ссылочный тип, возвращает указатель на объект. Вы дали вызывающей стороне ссылку на внутренний объект, поэтому ей больше не нужно использовать ваш объект для манипуляции с внутренним объектом.
Очевидно, что вы хотите предотвратить подобное поведение. Вы создали интерфейс для своего класса и хотите, чтобы пользователи использовали его, а не изменяли внутреннее состояние ваших объектов без вашего ведома. Для защиты внутренних данных от непреднамеренных изменений есть 4 стратегии: типы значений, неизменяемые типы, интерфейсы и оболочки.
1. Типы значений копируются, когда клиенты обращаются к ним через свойство. Любые изменения копии, полученной клиентами вашего класса, не влияют на внутреннее состояние вашего объекта.
2. Неизменяемые типы, такие как
3. Интерфейсы позволяют клиентам получать доступ к подмножеству функционала вашего внутреннего члена. Предоставляя функциональность через интерфейс, вы сводите к минимуму вероятность того, что ваши внутренние данные изменятся не так, как вы предполагали. Клиенты могут получить доступ к внутреннему объекту через предоставленный вами интерфейс, который не будет включать в себя все функции класса. В нашем случае публичное свойство можно представлять клиентам в виде
4. Последний вариант – предоставить объект-оболочку, минимизирующую варианты доступа к содержащемуся объекту. В .NET представлены различные типы неизменяемых коллекций, которые это поддерживают. Тип
Предоставление ссылочных типов через общедоступный интерфейс позволяет пользователям вашего объекта изменять его внутренние компоненты, не используя методы и свойства, которые вы определили. Необходимо изменить интерфейсы вашего класса, чтобы учесть, что вы отдаёте ссылки, а не значения. Ваши клиенты могут вызывать любые методы предоставленных им объектов. Ограничьте доступ, предоставляя внутренние данные с помощью интерфейсов, оболочек или типов значений.
Источник: Bill Wagner “More Effective C#”. – 2nd ed. Глава 17.
17. Избегайте Возврата Ссылок на Внутренний Класс
Вы можете думать, что свойство только для чтения доступно только для чтения и вызывающие объекты не могут его изменять. К сожалению, так получается не всегда. Если свойство возвращает ссылочный тип, вызывающий код может получить доступ к любому общедоступному члену этого объекта, включая те, которые изменяют его состояние. Например:
public class MyObject {Получаем доступ к списку и удаляем его элементы. Это поведение не предусмотрено, но и не запрещено:
public MyObject() {
Data = new List<ImportantData>();
}
public List<ImportantData> Data { get; }
…
}
var stuff = obj.Data;Таким образом свойство только для чтения - дыра в продуманной инкапсуляции вашего класса. Не говоря уже о том, что создатель класса рассматривает это свойство как неизменяемое и не ожидает подвоха.
stuff.Clear();
Добро пожаловать в чудесный мир ссылочных типов. Любой член, возвращающий ссылочный тип, возвращает указатель на объект. Вы дали вызывающей стороне ссылку на внутренний объект, поэтому ей больше не нужно использовать ваш объект для манипуляции с внутренним объектом.
Очевидно, что вы хотите предотвратить подобное поведение. Вы создали интерфейс для своего класса и хотите, чтобы пользователи использовали его, а не изменяли внутреннее состояние ваших объектов без вашего ведома. Для защиты внутренних данных от непреднамеренных изменений есть 4 стратегии: типы значений, неизменяемые типы, интерфейсы и оболочки.
1. Типы значений копируются, когда клиенты обращаются к ним через свойство. Любые изменения копии, полученной клиентами вашего класса, не влияют на внутреннее состояние вашего объекта.
2. Неизменяемые типы, такие как
System.String
, также безопасны. Вы можете возвращать строки или любые неизменяемые типы, зная, что ни один клиент вашего класса не сможет их изменить.3. Интерфейсы позволяют клиентам получать доступ к подмножеству функционала вашего внутреннего члена. Предоставляя функциональность через интерфейс, вы сводите к минимуму вероятность того, что ваши внутренние данные изменятся не так, как вы предполагали. Клиенты могут получить доступ к внутреннему объекту через предоставленный вами интерфейс, который не будет включать в себя все функции класса. В нашем случае публичное свойство можно представлять клиентам в виде
IEnumerable<T>
вместо List<T>
.4. Последний вариант – предоставить объект-оболочку, минимизирующую варианты доступа к содержащемуся объекту. В .NET представлены различные типы неизменяемых коллекций, которые это поддерживают. Тип
System.Collections.ObjectModel.ReadOnlyCollection<T>
- это стандартный способ обернуть коллекцию для предоставления во вне данных только для чтения:public class MyObject {Итого
private List<ImportantData> listOfData =
new List<ImportantData>();
public ReadOnlyCollection<ImportantData> Data =>
new ReadOnlyCollection<ImportantData>(listOfData);
…
}
Предоставление ссылочных типов через общедоступный интерфейс позволяет пользователям вашего объекта изменять его внутренние компоненты, не используя методы и свойства, которые вы определили. Необходимо изменить интерфейсы вашего класса, чтобы учесть, что вы отдаёте ссылки, а не значения. Ваши клиенты могут вызывать любые методы предоставленных им объектов. Ограничьте доступ, предоставляя внутренние данные с помощью интерфейсов, оболочек или типов значений.
Источник: Bill Wagner “More Effective C#”. – 2nd ed. Глава 17.
День пятьсот девяносто восьмой. #Оффтоп #ЗадачиНаСобеседовании
Как насчёт задачки на выходные?)))
Думаю, большинство застало кнопочные телефоны с буками. А олды ещё помнят, что буквы были и на стационарных телефонах, особенно импортных (см. картинку).
На самом деле это довольно популярная система в основном в США для запоминания «красивых» корпоративных номеров. Номеров типа
Итак, к задаче. Дан номер телефона, например
Нужно определить, какие слова из списка содержатся в номере телефона. Номер телефона может быть разной длины, но в разумных пределах. Слова должны содержаться целиком как подстроки.
Как насчёт задачки на выходные?)))
Думаю, большинство застало кнопочные телефоны с буками. А олды ещё помнят, что буквы были и на стационарных телефонах, особенно импортных (см. картинку).
На самом деле это довольно популярная система в основном в США для запоминания «красивых» корпоративных номеров. Номеров типа
8-800-700-8000
(кстати, это техподдержка Билайна, не спрашивайте, почему я его помню) на всех не хватит. Тогда придумали расположить алфавит на кнопках, и клиент должен был просто нажимать кнопки, соответствующие буквам. Например:1-800-flowers
означало номер 1-800-3569377
Сам номер «некрасивый», а слово легко запомнить.Итак, к задаче. Дан номер телефона, например
3662277
и список слов, например ["foo", "bar", "baz", "foobar", "cap", "car", "cat"]
.Нужно определить, какие слова из списка содержатся в номере телефона. Номер телефона может быть разной длины, но в разумных пределах. Слова должны содержаться целиком как подстроки.
День пятьсот девяносто девятый. #Оффтоп
Чистый Код
Воскресное ненапряжное – сказка от дядюшки Боба. Видео древнее, как Windows XP, но почему-то раньше мне не попадалось.
В этом видео дядя Боб показывает, почему так важен чистый код, объясняет, как плохой код ведет к нисходящей спирали «Ловушки производительности», а также описывает разные формы «гниения кода».
В общем, «Чистый код» и «Мифический человеко-месяц» в одном часовом видео с шутками, прибаутками и отсылками к «Звёздным войнам», «Шерлоку», «Стар-треку» и куче всего другого. Энджой!
https://www.youtube.com/watch?v=Wibk0IfjfaI
Чистый Код
Воскресное ненапряжное – сказка от дядюшки Боба. Видео древнее, как Windows XP, но почему-то раньше мне не попадалось.
В этом видео дядя Боб показывает, почему так важен чистый код, объясняет, как плохой код ведет к нисходящей спирали «Ловушки производительности», а также описывает разные формы «гниения кода».
В общем, «Чистый код» и «Мифический человеко-месяц» в одном часовом видео с шутками, прибаутками и отсылками к «Звёздным войнам», «Шерлоку», «Стар-треку» и куче всего другого. Энджой!
https://www.youtube.com/watch?v=Wibk0IfjfaI
YouTube
FULL EPISODE // Clean Code with Uncle Bob Episode 1
To see more about Clean Coders:
https://cleancoders.com/
Get ready for something very different. This ain't no screen cast. This ain't no talkin' head lecture. This is an _Uncle Bob video!_
This is like watching Uncle Bob on stage, but more so. This is…
https://cleancoders.com/
Get ready for something very different. This ain't no screen cast. This ain't no talkin' head lecture. This is an _Uncle Bob video!_
This is like watching Uncle Bob on stage, but more so. This is…
День шестисотый.
Очередной юбилей, 600 дней дневнику.
Сегодня немного расскажу о текущем положении вещей в проектах.
Я продолжаю подготовку к экзамену 70-486. Приблизительно наметил дату сдачи на конец октября – начало ноября. Я в принципе прошёл по темам экзамена, осталось закрепить материал, особенно по Azure. Поэтому решил пройти несколько курсов на Pluralsight:
- ASP.NET Core
- .NET Developer on Microsoft Azure
- Microsoft Azure Compute for Developers
- Continuous Delivery and DevOps With Azure DevOps
Кроме того, на Microsoft Learn нашёл несколько интересных курсов:
- Deploy a website to Azure with Azure App Service
- Migrate an ASP.NET web application to Azure with Visual Studio
- Work with relational data in Azure
Не уверен, что посмотрю всё, но попробую. Может и кому из вас пригодится.
Кроме того, как я недавно писал, в конце сентября будет онлайн курс «Modernizing Web Applications and Data».
Что касается проекта «Путь разработчика». Спасибо всем за предложения в issues. Большинство из них были учтены и добавлены в описание. Кроме того, возникла идея реализовать Чистую архитектуру и паттерн CQRS. Кому интересно, вот тут составил плейлист по этим темам (извините, видео только на английском). За идею спасибо участникам чата. Они, кстати, решили написать другой проект по автоматизации системы учёта потребления газа. И поскольку старт моего проекта немного затягивается, кому не терпится попробовать свои силы, добро пожаловать. Публикую ссылку на группу с их разрешения. Многие идеи и технологии разработки и менеджмента проекта будут опробованы там и взяты в наш проект.
Очередной юбилей, 600 дней дневнику.
Сегодня немного расскажу о текущем положении вещей в проектах.
Я продолжаю подготовку к экзамену 70-486. Приблизительно наметил дату сдачи на конец октября – начало ноября. Я в принципе прошёл по темам экзамена, осталось закрепить материал, особенно по Azure. Поэтому решил пройти несколько курсов на Pluralsight:
- ASP.NET Core
- .NET Developer on Microsoft Azure
- Microsoft Azure Compute for Developers
- Continuous Delivery and DevOps With Azure DevOps
Кроме того, на Microsoft Learn нашёл несколько интересных курсов:
- Deploy a website to Azure with Azure App Service
- Migrate an ASP.NET web application to Azure with Visual Studio
- Work with relational data in Azure
Не уверен, что посмотрю всё, но попробую. Может и кому из вас пригодится.
Кроме того, как я недавно писал, в конце сентября будет онлайн курс «Modernizing Web Applications and Data».
Что касается проекта «Путь разработчика». Спасибо всем за предложения в issues. Большинство из них были учтены и добавлены в описание. Кроме того, возникла идея реализовать Чистую архитектуру и паттерн CQRS. Кому интересно, вот тут составил плейлист по этим темам (извините, видео только на английском). За идею спасибо участникам чата. Они, кстати, решили написать другой проект по автоматизации системы учёта потребления газа. И поскольку старт моего проекта немного затягивается, кому не терпится попробовать свои силы, добро пожаловать. Публикую ссылку на группу с их разрешения. Многие идеи и технологии разработки и менеджмента проекта будут опробованы там и взяты в наш проект.