Channel: .NET Разработчик
День 2221. #ЗаметкиНаПолях
Как Компилятор Выводит Тип из default?
Ключевое слово default — мощный инструмент в C#. Для ссылочных типов он возвращает null, а для типов значений (структур) — обнулённое значение. Интересно, что default(T) и new T() могут давать разные результаты для структур. Изначально C# требовал default(T), но теперь вы можете просто использовать default, когда тип может быть выведен компилятором. Но как компилятор выводит тип? И всегда ли вы можете доверять, что он сделает это правильно?
Давайте рассмотрим два простых случая:
Предыдущие случаи довольно очевидны, но что будет с выражением switch?
Вы можете ожидать, что default будет default(ReadOnlyMemory<byte>), так как это видимый тип в левой части. Однако на самом деле это будет default(byte[]). Компилятор выводит тип из ветвей выражения switch. В этом случае компилятор определит наилучший общий тип для всех случаев, которым в данном случае является byte[]. Следовательно, типом default будет byte[].
В предыдущем примере результат foo не поменяется, если вы используете default(byte[]) или default(ReadOnlyMemory<byte>). Но это может иметь некоторые последствия. Давайте изменим тип с ReadOnlyMemory<byte> на ReadOnlyMemory<byte>? (обнуляемый).
В этом примере типом default всё ещё будет default(byte[]). Поэтому выражение switch вернёт default(byte[]), что является null. Однако, затем значение будет преобразовано в ReadOnlyMemory<byte>?. А у ReadOnlyMemory<T> есть оператор неявного преобразования из массива:
В свою очередь, конструктор ReadOnlyMemory<T>, принимающий обнуляемый массив, создаёт пустой ReadOnlyMemory<T>, если получает null:
Таким образом, на выходе мы получим пустой ReadOnlyMemory<byte>, и foo.HasValue будет true!
А если мы явно укажем обнуляемый тип в default:
Тогда закономерно получим null в выражении switch, и foo.HasValue будет false.
Источник: https://www.meziantou.net/how-does-the-compiler-infer-the-type-of-default.htm
Как Компилятор Выводит Тип из default?
Ключевое слово default — мощный инструмент в C#. Для ссылочных типов он возвращает null, а для типов значений (структур) — обнулённое значение. Интересно, что default(T) и new T() могут давать разные результаты для структур. Изначально C# требовал default(T), но теперь вы можете просто использовать default, когда тип может быть выведен компилятором. Но как компилятор выводит тип? И всегда ли вы можете доверять, что он сделает это правильно?
Давайте рассмотрим два простых случая:
// Выведение типа из левой части
int foo = default;
// Выведение типа из типа параметра
Foo(default);
void Foo(int bar) => throw null;
Предыдущие случаи довольно очевидны, но что будет с выражением switch?
var sample = new byte[0];
ReadOnlyMemory<byte> foo = sample switch
{
byte[] value => value,
_ => default
};
Вы можете ожидать, что default будет default(ReadOnlyMemory<byte>), так как это видимый тип в левой части. Однако на самом деле это будет default(byte[]). Компилятор выводит тип из ветвей выражения switch. В этом случае компилятор определит наилучший общий тип для всех случаев, которым в данном случае является byte[]. Следовательно, типом default будет byte[].
В предыдущем примере результат foo не поменяется, если вы используете default(byte[]) или default(ReadOnlyMemory<byte>). Но это может иметь некоторые последствия. Давайте изменим тип с ReadOnlyMemory<byte> на ReadOnlyMemory<byte>? (обнуляемый).
var sample = new object();
ReadOnlyMemory<byte>? foo = sample switch
{
byte[] value => value,
_ => default
};
В этом примере типом default всё ещё будет default(byte[]). Поэтому выражение switch вернёт default(byte[]), что является null. Однако, затем значение будет преобразовано в ReadOnlyMemory<byte>?. А у ReadOnlyMemory<T> есть оператор неявного преобразования из массива:
// из исходного кода .NET 9
public static implicit operator
ReadOnlyMemory<T>(T[]? array)
=> new ReadOnlyMemory<T>(array);
В свою очередь, конструктор ReadOnlyMemory<T>, принимающий обнуляемый массив, создаёт пустой ReadOnlyMemory<T>, если получает null:
// из исходного кода .NET 9
public ReadOnlyMemory(T[]? array)
{
if (array == null)
{
this = default;
return; // returns default
}
…
}
Таким образом, на выходе мы получим пустой ReadOnlyMemory<byte>, и foo.HasValue будет true!
А если мы явно укажем обнуляемый тип в default:
object sample = new();
ReadOnlyMemory<byte>? foo = sample switch
{
byte[] value => value,
_ => default(ReadOnlyMemory<byte>?)
};
Тогда закономерно получим null в выражении switch, и foo.HasValue будет false.
Источник: https://www.meziantou.net/how-does-the-compiler-infer-the-type-of-default.htm
4👍18
День 2222. #УрокиРазработки
Уроки 50 Лет Разработки ПО
Качество. Начало
Качественное ПО важно для всех, кто создает или использует программные системы. Но что такое качество?
Разные наблюдатели всегда будут иметь разные представления о том, какие черты данного продукта или услуги определяют качество или его отсутствие. Качество имеет множество аспектов и понятие качества зависит от ситуации. В контексте ПО понятие качества описывает, насколько хорошо продукт выполняет всё, что от него требуется, и дать более строгое определение, вероятно, не получится. И все же каждая проектная группа должна изучить, что ее клиенты понимают под качеством, как его оценить и достичь, а затем в ясной форме передать эти знания всем участникам проекта. В идеальном мире каждый проект должен предоставлять продукт, содержащий все функции, которые когда-либо потребуются любому пользователю, не имеющий дефектов и идеально удобный, произве¬денный в рекордно короткие сроки и с минимальными затратами. Но это фантазия; ожидания в отношении качества должны быть реалистичными. Лица, принимающие решения по каждому проекту, должны определить, какие аспекты наиболее важны для успеха проекта и на какие компромиссы они могут пойти, преследуя свои бизнес-цели.
Планирование качества
Команды разработчиков и руководители иногда решают пойти на компромисс в отношении качества, чтобы уложиться в срок, или включить более богатый, хотя и несовершенный, набор функций, делающих их продукт более привлекательным для клиентов. Поэтому модель из урока 31 содержит качество как явный параметр проекта. Люди, принимающие решения о выпуске, могут смириться с существованием неких известных дефектов, если, по их мнению, эти дефекты не будут оказывать большого влияния на клиентов или бизнес. Однако пользователи могут не согласиться с этим. ПО необязательно должно иметь множество проблем, чтобы произвести впечатление низкокачественного. Если любимая функция поль¬зователя будет иметь дефект, то пользователь, скорее всего, сочтёт весь продукт проблемным и расскажет об этом всем, кого знает.
Команды разработчиков выиграют от создания плана управления качеством в начале проекта. В плане должны быть определены реалистичные ожидания в отношении качества продукта, включая классификацию серьезности дефектов (серьёзные, умеренные, незначительные, косметические). Это поможет создать у всех участников проекта согласованное представление о понятии качества. Определение общей терминологии и ожиданий в отношении различных видов тестирования дополнительно поможет сблизить заинтересованные стороны, позволяя достичь общей цели — создания высококачественного решения.
Несколько взглядов на качество
Качество ПО - это больше, чем простое соответствие заданным требованиям, и больше, чем отсутствие дефектов. Необходимо учитывать многочисленные характеристики: функциональные возможности, эстетику, производительность, надёжность, удобство использования, стоимость, своевременность доставки и т.д. Поскольку невозможно создать продукт, идеальный по всем параметрам, часто приходится идти на компромиссы в отношении качества. Атрибуты качества должны быть точно определены и расставлены по приоритетам, чтобы те, кто принимает решения, могли сделать правильный выбор.
Кроме того, заинтересованные стороны могут по-разному воспринимать качество. Разработчик может считать, что высококачественный код должен быть написан элегантно и выполняться эффективно и правильно. Специалист по сопровождению оценит более простой и понятный код. Они сосредоточены на внутреннем качестве продукта. Пользователю же интереснее внешнее качество.
Окончание следует…
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 6.
Уроки 50 Лет Разработки ПО
Качество. Начало
Качественное ПО важно для всех, кто создает или использует программные системы. Но что такое качество?
Разные наблюдатели всегда будут иметь разные представления о том, какие черты данного продукта или услуги определяют качество или его отсутствие. Качество имеет множество аспектов и понятие качества зависит от ситуации. В контексте ПО понятие качества описывает, насколько хорошо продукт выполняет всё, что от него требуется, и дать более строгое определение, вероятно, не получится. И все же каждая проектная группа должна изучить, что ее клиенты понимают под качеством, как его оценить и достичь, а затем в ясной форме передать эти знания всем участникам проекта. В идеальном мире каждый проект должен предоставлять продукт, содержащий все функции, которые когда-либо потребуются любому пользователю, не имеющий дефектов и идеально удобный, произве¬денный в рекордно короткие сроки и с минимальными затратами. Но это фантазия; ожидания в отношении качества должны быть реалистичными. Лица, принимающие решения по каждому проекту, должны определить, какие аспекты наиболее важны для успеха проекта и на какие компромиссы они могут пойти, преследуя свои бизнес-цели.
Планирование качества
Команды разработчиков и руководители иногда решают пойти на компромисс в отношении качества, чтобы уложиться в срок, или включить более богатый, хотя и несовершенный, набор функций, делающих их продукт более привлекательным для клиентов. Поэтому модель из урока 31 содержит качество как явный параметр проекта. Люди, принимающие решения о выпуске, могут смириться с существованием неких известных дефектов, если, по их мнению, эти дефекты не будут оказывать большого влияния на клиентов или бизнес. Однако пользователи могут не согласиться с этим. ПО необязательно должно иметь множество проблем, чтобы произвести впечатление низкокачественного. Если любимая функция поль¬зователя будет иметь дефект, то пользователь, скорее всего, сочтёт весь продукт проблемным и расскажет об этом всем, кого знает.
Команды разработчиков выиграют от создания плана управления качеством в начале проекта. В плане должны быть определены реалистичные ожидания в отношении качества продукта, включая классификацию серьезности дефектов (серьёзные, умеренные, незначительные, косметические). Это поможет создать у всех участников проекта согласованное представление о понятии качества. Определение общей терминологии и ожиданий в отношении различных видов тестирования дополнительно поможет сблизить заинтересованные стороны, позволяя достичь общей цели — создания высококачественного решения.
Несколько взглядов на качество
Качество ПО - это больше, чем простое соответствие заданным требованиям, и больше, чем отсутствие дефектов. Необходимо учитывать многочисленные характеристики: функциональные возможности, эстетику, производительность, надёжность, удобство использования, стоимость, своевременность доставки и т.д. Поскольку невозможно создать продукт, идеальный по всем параметрам, часто приходится идти на компромиссы в отношении качества. Атрибуты качества должны быть точно определены и расставлены по приоритетам, чтобы те, кто принимает решения, могли сделать правильный выбор.
Кроме того, заинтересованные стороны могут по-разному воспринимать качество. Разработчик может считать, что высококачественный код должен быть написан элегантно и выполняться эффективно и правильно. Специалист по сопровождению оценит более простой и понятный код. Они сосредоточены на внутреннем качестве продукта. Пользователю же интереснее внешнее качество.
Окончание следует…
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 6.
👍9
День 2223. #УрокиРазработки
Уроки 50 Лет Разработки ПО
Качество. Окончание
Начало
Последовательное обеспечение качества
Повышение качества, не считая косметических и эстетических улучшений, — сложная задача. Нельзя просто написать несколько целей доступности в пользовательской истории и добавить её в требования продукта для реализации в одной из будущих итераций разработки. Удовлетворение некоторых критериев качества влечёт архитектурные последствия, которые команда должна учитывать с самого начала проекта. Трудно обеспечить высокое качество продукта, построенного на шатком фундаменте. Пытаясь уложиться в срок за счёт экономии времени на реализации некоторых возможностей, разработчики будут накапливать технический долг, что ещё больше усложнит модификацию и расширение кодовой базы. Технический долг определённо относится к накопленным недостаткам качества реализованного ПО.
В общие затраты, связанные с качеством, входит стоимость всех работ, выполняемых для предотвращения, обнаружения и исправления дефектов. Бизнес-аналитики, разработчики и другие участники проекта будут совершать ошибки — это, увы, неизбежно. Поэтому необходимо принять на вооружение технические методы, которые помогут свести к минимуму количество создаваемых дефектов, развивать личную этику и организационную культуру, которые способствуют предотвращению дефектов и их раннему обнаружению.
Не всякий продукт должен быть идеальным, но каждый должен положительно оцениваться пользователями и другими заинтересованными сторонами. Первые пользователи инновационных продуктов относятся терпимо к дефектам, пока продукт позволяет им делать что-то новое. В других же областях, таких как медицина или авиация, к качеству программных продуктов предъявляются гораздо более строгие требования. Первый шаг для любой проектной группы — решить, что означает качество для их продукта во всех его видах.
Первые шаги
1. Как в вашей организации определяется внутреннее (с точки зрения разработчиков и специалистов по сопровождению) и внешнее (с точки зрения конечных пользователей) качество продуктов?
2. Документируют ли ваши проектные группы, что подразумевает понятие качества для каждого из их проектов? Ставят ли они измеримые цели в области качества?
3. Как в вашей организации оценивается соответствие каждого продукта ожиданиям в отношении качества со стороны команды и клиентов?
4. Перечислите методы поддержания качества ПО, в которых ваша организация особенно преуспела. Задокументирована ли информация об этих методах? Доступна ли она другим членам команды, чтобы они могли ознакомиться с этими методами и применять на практике?
5. Определите любые проблемы (болевые точки), которые можно отнести к недостаткам в том, как ваши команды подходят к вопросам качества ПО.
6. Как каждая проблема влияет на вашу способность успешно завершать проекты. Как все они мешают достижению успеха в бизнесе и организации, и её клиентам? Проблемы с качеством приводят как к материальным, так и к нематериальным затратам, таким как незапланированные доработки, задержки, расходы на поддержку и техническое обслуживание, неудовлетворённость клиентов и нелестные отзывы о продуктах.
7. Для каждой проблемы, выявленной на шаге 5, определите основные причины, провоцирующие или усугубляющие её. Проблемы, влияния и первопричины могут сливаться, поэтому постарайтесь разделить их и увидеть, как они связаны. Вы можете найти несколько основных причин, способствующих появлению одной и той же проблемы, или несколько проблем, обусловленных одной общей причиной.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 6.
Уроки 50 Лет Разработки ПО
Качество. Окончание
Начало
Последовательное обеспечение качества
Повышение качества, не считая косметических и эстетических улучшений, — сложная задача. Нельзя просто написать несколько целей доступности в пользовательской истории и добавить её в требования продукта для реализации в одной из будущих итераций разработки. Удовлетворение некоторых критериев качества влечёт архитектурные последствия, которые команда должна учитывать с самого начала проекта. Трудно обеспечить высокое качество продукта, построенного на шатком фундаменте. Пытаясь уложиться в срок за счёт экономии времени на реализации некоторых возможностей, разработчики будут накапливать технический долг, что ещё больше усложнит модификацию и расширение кодовой базы. Технический долг определённо относится к накопленным недостаткам качества реализованного ПО.
В общие затраты, связанные с качеством, входит стоимость всех работ, выполняемых для предотвращения, обнаружения и исправления дефектов. Бизнес-аналитики, разработчики и другие участники проекта будут совершать ошибки — это, увы, неизбежно. Поэтому необходимо принять на вооружение технические методы, которые помогут свести к минимуму количество создаваемых дефектов, развивать личную этику и организационную культуру, которые способствуют предотвращению дефектов и их раннему обнаружению.
Не всякий продукт должен быть идеальным, но каждый должен положительно оцениваться пользователями и другими заинтересованными сторонами. Первые пользователи инновационных продуктов относятся терпимо к дефектам, пока продукт позволяет им делать что-то новое. В других же областях, таких как медицина или авиация, к качеству программных продуктов предъявляются гораздо более строгие требования. Первый шаг для любой проектной группы — решить, что означает качество для их продукта во всех его видах.
Первые шаги
1. Как в вашей организации определяется внутреннее (с точки зрения разработчиков и специалистов по сопровождению) и внешнее (с точки зрения конечных пользователей) качество продуктов?
2. Документируют ли ваши проектные группы, что подразумевает понятие качества для каждого из их проектов? Ставят ли они измеримые цели в области качества?
3. Как в вашей организации оценивается соответствие каждого продукта ожиданиям в отношении качества со стороны команды и клиентов?
4. Перечислите методы поддержания качества ПО, в которых ваша организация особенно преуспела. Задокументирована ли информация об этих методах? Доступна ли она другим членам команды, чтобы они могли ознакомиться с этими методами и применять на практике?
5. Определите любые проблемы (болевые точки), которые можно отнести к недостаткам в том, как ваши команды подходят к вопросам качества ПО.
6. Как каждая проблема влияет на вашу способность успешно завершать проекты. Как все они мешают достижению успеха в бизнесе и организации, и её клиентам? Проблемы с качеством приводят как к материальным, так и к нематериальным затратам, таким как незапланированные доработки, задержки, расходы на поддержку и техническое обслуживание, неудовлетворённость клиентов и нелестные отзывы о продуктах.
7. Для каждой проблемы, выявленной на шаге 5, определите основные причины, провоцирующие или усугубляющие её. Проблемы, влияния и первопричины могут сливаться, поэтому постарайтесь разделить их и увидеть, как они связаны. Вы можете найти несколько основных причин, способствующих появлению одной и той же проблемы, или несколько проблем, обусловленных одной общей причиной.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 6.
👍6👎2
День 2224. #ЧтоНовенького #NET10
Новые Функции в С#14
Выпущен первый превью .NET 10. Давайте взглянем на парочку первых потенциальных дополнений к языку.
1. Null-условное присваивание
Основная проблема, которую здесь пытаются решить, выглядит примерно так: представьте, что у вас есть переменная, которая может быть null. Если это не так, вы хотите присвоить значение её свойству. Вот как это делается сейчас:
Предложено упростить код выше до следующего:
Таким образом, если myObj не null, будет сделано присваивание свойству Property. В противном случае – нет. По сути, это очередной синтаксический сахар, который может приводить к «прекрасным» присвоениям вроде такого:
2. Аллокация массивов типов значений на стеке
В .NET 9 JIT уже получил возможность аллоцировать объекты на стеке, когда объект гарантированно не переживёт свой родительский метод (например, когда объект – переменная внутри метода). Аллокация на стеке не только уменьшает количество объектов, которые должен отслеживать GC, но и открывает другие возможности оптимизации: например, после аллокации объекта на стеке JIT может рассмотреть возможность полной его замены на скалярные значения.
В .NET 10 JIT теперь будет выделять в стеке и небольшие массивы фиксированного размера, состоящие из типов значений, не содержащих ссылок, на условиях, описанных выше (существование внутри метода). Рассмотрим следующий пример:
Поскольку JIT знает, что numbers — это массив, создаваемый во время компиляции и состоящий всего из трёх целых чисел, а также он не переживёт метод Sum, то JIT аллоцирует его на стеке.
В следующих превью версиях среди других улучшений аллокаций на стеке планируется расширить эту возможность на массивы ссылочных типов.
Источники:
- https://steven-giesel.com/blogPost/b6d22649-7fba-488b-b252-31efdb3686c5/c-14-nullconditional-assignment
- https://github.com/dotnet/core/blob/main/release-notes/10.0/preview/preview1/runtime.md#stack-allocation-of-arrays-of-value-types
Новые Функции в С#14
Выпущен первый превью .NET 10. Давайте взглянем на парочку первых потенциальных дополнений к языку.
1. Null-условное присваивание
Основная проблема, которую здесь пытаются решить, выглядит примерно так: представьте, что у вас есть переменная, которая может быть null. Если это не так, вы хотите присвоить значение её свойству. Вот как это делается сейчас:
MyObject? myObj = GetMyObjectOrNull();
if (myObj is not null)
{
myObj.Property = 100;
}
Предложено упростить код выше до следующего:
MyObject? myObj = GetMyObjectOrNull ();
myObj?.Property = 100;
Таким образом, если myObj не null, будет сделано присваивание свойству Property. В противном случае – нет. По сути, это очередной синтаксический сахар, который может приводить к «прекрасным» присвоениям вроде такого:
MyDeeplyNestedObj? m = FromSomewhere();
m?.A?.B?.C?.D = "Foo Bar";
2. Аллокация массивов типов значений на стеке
В .NET 9 JIT уже получил возможность аллоцировать объекты на стеке, когда объект гарантированно не переживёт свой родительский метод (например, когда объект – переменная внутри метода). Аллокация на стеке не только уменьшает количество объектов, которые должен отслеживать GC, но и открывает другие возможности оптимизации: например, после аллокации объекта на стеке JIT может рассмотреть возможность полной его замены на скалярные значения.
В .NET 10 JIT теперь будет выделять в стеке и небольшие массивы фиксированного размера, состоящие из типов значений, не содержащих ссылок, на условиях, описанных выше (существование внутри метода). Рассмотрим следующий пример:
static void Sum()
{
int[] numbers = {1, 2, 3};
int sum = 0;
for (int i = 0; i < numbers.Length; i++)
{
sum += numbers[i];
}
Console.WriteLine(sum);
}
Поскольку JIT знает, что numbers — это массив, создаваемый во время компиляции и состоящий всего из трёх целых чисел, а также он не переживёт метод Sum, то JIT аллоцирует его на стеке.
В следующих превью версиях среди других улучшений аллокаций на стеке планируется расширить эту возможность на массивы ссылочных типов.
Источники:
- https://steven-giesel.com/blogPost/b6d22649-7fba-488b-b252-31efdb3686c5/c-14-nullconditional-assignment
- https://github.com/dotnet/core/blob/main/release-notes/10.0/preview/preview1/runtime.md#stack-allocation-of-arrays-of-value-types
1👍36
День 2225. #ЗаметкиНаПолях
UUID и ULID в .NET
Хотя UUID (универсальные уникальные идентификаторы) были отраслевым стандартом в течение многих лет, ULID (универсальные уникальные лексикографически сортируемые идентификаторы) являются превосходной альтернативой в определённых контекстах. Про сортируемые GUID, появившиеся в .NET 9 я уже писал ранее. Сегодня рассмотрим их альтернативу (например, если вы ещё не перешли на .NET 9).
Стандартный формат для UUID:
13й символ – это версия UUID, а 17й – обозначает вариант (вид и значение UUID).
UUID, особенно версии 4, являются в высокой степени случайными. Эта случайность, хотя и обеспечивает уникальность, может привести к узким местам производительности в базах данных из-за низкой эффективности индексации.
ULID решают некоторые ограничения производительности и сортировки UUID. Они объединяют временную метку со случайными данными для создания 128-битного идентификатора, который можно сортировать лексикографически. Типичный ULID выглядит следующим образом:
ULID состоит из метки времени Unix в миллисекундах (первые 10 символов) и случайно сгенерированных остальных символов.
Чтобы использовать ULID в .NET, нужно установить NuGet-пакет Ulid (доступен во всех версиях .NET, даже в .NET Framework):
Преимущества
- Лексикографическая сортировка, что значительно повышает индексацию базы данных и производительность запросов.
- Совместимость: ULID имеют длину 128 бит, что обеспечивает совместимость с системами, разработанными для UUID.
Пример использования: интеграция с Entity Framework
Чтобы использовать ULID в Entity Framework, вы можете настроить модели на использование ULID в качестве первичных ключей:
Источник: https://medium.com/codenx/uuid-and-ulid-in-net-maximizing-efficiency-in-unique-identifiers-a94c41177128
UUID и ULID в .NET
Хотя UUID (универсальные уникальные идентификаторы) были отраслевым стандартом в течение многих лет, ULID (универсальные уникальные лексикографически сортируемые идентификаторы) являются превосходной альтернативой в определённых контекстах. Про сортируемые GUID, появившиеся в .NET 9 я уже писал ранее. Сегодня рассмотрим их альтернативу (например, если вы ещё не перешли на .NET 9).
Стандартный формат для UUID:
afdf5738–6a8e-4d1a-90db-e894a3828320
13й символ – это версия UUID, а 17й – обозначает вариант (вид и значение UUID).
UUID, особенно версии 4, являются в высокой степени случайными. Эта случайность, хотя и обеспечивает уникальность, может привести к узким местам производительности в базах данных из-за низкой эффективности индексации.
ULID решают некоторые ограничения производительности и сортировки UUID. Они объединяют временную метку со случайными данными для создания 128-битного идентификатора, который можно сортировать лексикографически. Типичный ULID выглядит следующим образом:
01HZW2RKF63AWC1BT901FPGRGT
ULID состоит из метки времени Unix в миллисекундах (первые 10 символов) и случайно сгенерированных остальных символов.
Чтобы использовать ULID в .NET, нужно установить NuGet-пакет Ulid (доступен во всех версиях .NET, даже в .NET Framework):
using System;
using NUlid;
Ulid newUlid = Ulid.NewUlid();
Console.WriteLine(newUlid.ToString());
Преимущества
- Лексикографическая сортировка, что значительно повышает индексацию базы данных и производительность запросов.
- Совместимость: ULID имеют длину 128 бит, что обеспечивает совместимость с системами, разработанными для UUID.
Пример использования: интеграция с Entity Framework
Чтобы использовать ULID в Entity Framework, вы можете настроить модели на использование ULID в качестве первичных ключей:
public class Order
{
[Key]
public Ulid OrderId { get; set; }
public DateTime OrderDate { get; set; }
// …
}
protected override void OnModelCreating(ModelBuilder mb)
{
mb.Entity<Order>()
.Property(o => o.OrderId)
.HasConversion(
v => v.ToString(),
v => Ulid.Parse(v));
}
Источник: https://medium.com/codenx/uuid-and-ulid-in-net-maximizing-efficiency-in-unique-identifiers-a94c41177128
👍17👎2
День 2226. #ЗаметкиНаПолях
Kafka и Event-Driven Архитектура. Начало
Kafka — это распределённая платформа потоковой передачи событий с открытым исходным кодом, предназначенная для обработки потоков данных в реальном времени.
Первоначально разработанная в LinkedIn, а затем с открытым кодом в Apache Software Foundation, Kafka теперь широко используется для создания высокопроизводительных, отказоустойчивых и масштабируемых конвейеров данных, аналитики в реальном времени и архитектур, управляемых событиями.
Какие проблемы решает?
До Kafka широко использовались традиционные очереди сообщений, такие как RabbitMQ и ActiveMQ, но у них были ограничения при обработке больших потоков данных в реальном времени с высокой пропускной способностью.
Kafka была разработана для решения этих проблем, предоставляя:
1. Обработку больших данных
Оптимизирована для приёма, хранения и распределения потоков данных большого объёма по распределённым системам.
2. Отказоустойчивость
Реплицирует данные на несколько узлов, гарантируя, что даже в случае сбоя брокера данные останутся доступными.
3. Долговечность
Сообщения сохраняются на диске, что позволяет потребителям воспроизводить события при необходимости.
4. Поддержку Event-Driven архитектуры
Обеспечивает асинхронную связь между микросервисами, что делает её идеальной для современных облачных приложений.
Когда использовать?
1. Сообщения
Kafka хорошо подойдёт в качестве замены более традиционному брокеру сообщений для отделения обработки от производителей данных, для буферизации необработанных сообщений и т.д. По сравнению с большинством систем обмена сообщениями Kafka имеет лучшую пропускную способность, встроенное партиционирование, репликацию и отказоустойчивость, что делает её хорошим решением для крупных приложений обработки сообщений.
2. Отслеживание активности веб-сайта
Первоначальным вариантом использования Kafka была возможность перестроить конвейер отслеживания активности пользователя в виде набора тем публикации-подписки в реальном времени. Это означает, что активность сайта (просмотры страниц, поиски или другие действия, которые могут выполнять пользователи) публикуется в темах по типу активности. Эти темы доступны для подписки для различных вариантов использования, включая обработку и мониторинг в реальном времени, загрузку в Hadoop или автономные системы хранения данных для автономной обработки и отчётности.
3. Метрики
Kafka часто используется для данных оперативного мониторинга: агрегации статистики из распределённых приложений для создания централизованных каналов оперативных данных.
4. Агрегация журналов
Агрегация журналов обычно собирает физические файлы журналов с серверов и помещает их в единое место для обработки. Kafka абстрагирует детали файлов и даёт более чистую абстракцию данных журнала или событий в виде потока сообщений. Это позволяет обрабатывать данные с меньшей задержкой и упрощает поддержку нескольких источников данных и распределённого потребления данных.
5. Потоковая обработка
Многие пользователи Kafka обрабатывают данные в конвейерах обработки, состоящих из нескольких этапов, где необработанные входные данные потребляются из тем Kafka, а затем агрегируются, обогащаются или иным образом преобразуются в новые темы для дальнейшего потребления или последующей обработки.
6. Event Sourcing
Это стиль проектирования приложений, в котором изменения состояния регистрируются как упорядоченная по времени последовательность записей. Поддержка Kafka очень больших хранимых данных журнала делает её отличным бэкэндом для приложений, созданных в этом стиле.
7. Журнал транзакций
Kafka может служить своего рода внешним журналом транзакций для распределённой системы. Журнал помогает реплицировать данные между узлами и действует как механизм повторной синхронизации для отказавших узлов для восстановления их данных.
Окончание следует…
Источники:
- https://dev.to/lovestaco/why-kafka-a-developer-friendly-guide-to-event-driven-architecture-4ekf
- https://kafka.apache.org
Kafka и Event-Driven Архитектура. Начало
Kafka — это распределённая платформа потоковой передачи событий с открытым исходным кодом, предназначенная для обработки потоков данных в реальном времени.
Первоначально разработанная в LinkedIn, а затем с открытым кодом в Apache Software Foundation, Kafka теперь широко используется для создания высокопроизводительных, отказоустойчивых и масштабируемых конвейеров данных, аналитики в реальном времени и архитектур, управляемых событиями.
Какие проблемы решает?
До Kafka широко использовались традиционные очереди сообщений, такие как RabbitMQ и ActiveMQ, но у них были ограничения при обработке больших потоков данных в реальном времени с высокой пропускной способностью.
Kafka была разработана для решения этих проблем, предоставляя:
1. Обработку больших данных
Оптимизирована для приёма, хранения и распределения потоков данных большого объёма по распределённым системам.
2. Отказоустойчивость
Реплицирует данные на несколько узлов, гарантируя, что даже в случае сбоя брокера данные останутся доступными.
3. Долговечность
Сообщения сохраняются на диске, что позволяет потребителям воспроизводить события при необходимости.
4. Поддержку Event-Driven архитектуры
Обеспечивает асинхронную связь между микросервисами, что делает её идеальной для современных облачных приложений.
Когда использовать?
1. Сообщения
Kafka хорошо подойдёт в качестве замены более традиционному брокеру сообщений для отделения обработки от производителей данных, для буферизации необработанных сообщений и т.д. По сравнению с большинством систем обмена сообщениями Kafka имеет лучшую пропускную способность, встроенное партиционирование, репликацию и отказоустойчивость, что делает её хорошим решением для крупных приложений обработки сообщений.
2. Отслеживание активности веб-сайта
Первоначальным вариантом использования Kafka была возможность перестроить конвейер отслеживания активности пользователя в виде набора тем публикации-подписки в реальном времени. Это означает, что активность сайта (просмотры страниц, поиски или другие действия, которые могут выполнять пользователи) публикуется в темах по типу активности. Эти темы доступны для подписки для различных вариантов использования, включая обработку и мониторинг в реальном времени, загрузку в Hadoop или автономные системы хранения данных для автономной обработки и отчётности.
3. Метрики
Kafka часто используется для данных оперативного мониторинга: агрегации статистики из распределённых приложений для создания централизованных каналов оперативных данных.
4. Агрегация журналов
Агрегация журналов обычно собирает физические файлы журналов с серверов и помещает их в единое место для обработки. Kafka абстрагирует детали файлов и даёт более чистую абстракцию данных журнала или событий в виде потока сообщений. Это позволяет обрабатывать данные с меньшей задержкой и упрощает поддержку нескольких источников данных и распределённого потребления данных.
5. Потоковая обработка
Многие пользователи Kafka обрабатывают данные в конвейерах обработки, состоящих из нескольких этапов, где необработанные входные данные потребляются из тем Kafka, а затем агрегируются, обогащаются или иным образом преобразуются в новые темы для дальнейшего потребления или последующей обработки.
6. Event Sourcing
Это стиль проектирования приложений, в котором изменения состояния регистрируются как упорядоченная по времени последовательность записей. Поддержка Kafka очень больших хранимых данных журнала делает её отличным бэкэндом для приложений, созданных в этом стиле.
7. Журнал транзакций
Kafka может служить своего рода внешним журналом транзакций для распределённой системы. Журнал помогает реплицировать данные между узлами и действует как механизм повторной синхронизации для отказавших узлов для восстановления их данных.
Окончание следует…
Источники:
- https://dev.to/lovestaco/why-kafka-a-developer-friendly-guide-to-event-driven-architecture-4ekf
- https://kafka.apache.org
👍14
День 2227. #ЗаметкиНаПолях
Kafka и Event-Driven Архитектура. Окончание
Начало
Kafka состоит из нескольких ключевых компонентов:
1. Сообщение
Наименьшая единица данных в Kafka: объект JSON, строка или любые двоичные данные. Сообщения могут иметь связанный ключ, который определяет, в каком разделе будет храниться сообщение.
2. Тема
Логический канал, по которому сообщения отправляются производителями и читаются потребителями. Темы помогают классифицировать сообщения (например, журналы, транзакции, заказы).
3. Производитель
Клиент Kafka, который публикует сообщения в теме. Сообщения можно отправлять тремя способами:
- Запустить и забыть — производитель отправляет сообщение, не дожидаясь подтверждения, что обеспечивает максимальную скорость, но рискует потерей данных.
- Синхронная отправка — производитель ждёт подтверждения от Kafka, прежде чем продолжить, что обеспечивает надёжность, но добавляет задержку.
- Асинхронная отправка — производитель отправляет сообщения партиями асинхронно, обеспечивая баланс между скоростью и надёжностью.
Подтверждения доставки (ACK) можно настраивать для баланса согласованности и производительности:
- ACK 0 — подтверждение не требуется (самый быстрый, но наиболее рискованный).
- ACK 1 — сообщение подтверждается, когда его получает ведущий брокер (быстрее, но менее безопасно).
- ACK All — сообщение подтверждается только тогда, когда все реплики подтверждают получение (медленнее, но наиболее безопасно).
Оптимизации производителя
- Сжатие и пакетирование сообщений перед отправкой их брокерам. Это повышает пропускную способность и снижает использование диска, но увеличивает нагрузку на ЦП.
- Сериализатор/десериализатор Avro вместо JSON требует предварительного определения схем, но повышает производительность и снижает потребление памяти.
4. Разделы (партиции)
Темы Kafka делятся на разделы, что обеспечивает параллельную обработку и масштабируемость. Сообщения в разделе упорядочены и неизменяемы.
5. Потребитель
Читает сообщения из разделов и отслеживает свою позицию с помощью смещения. Потребители могут сбрасывать смещения для повторной обработки старых сообщений. Потребители Kafka работают по модели опроса, то есть они постоянно запрашивают данные у брокера, а не брокер отправляет им данные.
6. Группа потребителей
Набор потребителей, которые работают вместе для обработки сообщений из темы. Kafka гарантирует, что один раздел потребляется только одним потребителем в группе, поддерживая порядок.
7. Управление смещением
Когда потребитель читает сообщение, он обновляет своё смещение — позицию последнего обработанного сообщения.
8. Брокер
Сервер Kafka, который хранит сообщения, назначает смещения и обрабатывает клиентские запросы. Несколько брокеров образуют кластер для масштабируемости и отказоустойчивости.
9. Zookeeper
Zookeeper управляет кластером: отслеживает брокеров, выбирает новый ведущий сервер при отказе и т.п. Однако более новые версии Kafka работают над устранением зависимости от Zookeeper.
Источник: https://dev.to/lovestaco/why-kafka-a-developer-friendly-guide-to-event-driven-architecture-4ekf
Kafka и Event-Driven Архитектура. Окончание
Начало
Kafka состоит из нескольких ключевых компонентов:
1. Сообщение
Наименьшая единица данных в Kafka: объект JSON, строка или любые двоичные данные. Сообщения могут иметь связанный ключ, который определяет, в каком разделе будет храниться сообщение.
2. Тема
Логический канал, по которому сообщения отправляются производителями и читаются потребителями. Темы помогают классифицировать сообщения (например, журналы, транзакции, заказы).
3. Производитель
Клиент Kafka, который публикует сообщения в теме. Сообщения можно отправлять тремя способами:
- Запустить и забыть — производитель отправляет сообщение, не дожидаясь подтверждения, что обеспечивает максимальную скорость, но рискует потерей данных.
- Синхронная отправка — производитель ждёт подтверждения от Kafka, прежде чем продолжить, что обеспечивает надёжность, но добавляет задержку.
- Асинхронная отправка — производитель отправляет сообщения партиями асинхронно, обеспечивая баланс между скоростью и надёжностью.
Подтверждения доставки (ACK) можно настраивать для баланса согласованности и производительности:
- ACK 0 — подтверждение не требуется (самый быстрый, но наиболее рискованный).
- ACK 1 — сообщение подтверждается, когда его получает ведущий брокер (быстрее, но менее безопасно).
- ACK All — сообщение подтверждается только тогда, когда все реплики подтверждают получение (медленнее, но наиболее безопасно).
Оптимизации производителя
- Сжатие и пакетирование сообщений перед отправкой их брокерам. Это повышает пропускную способность и снижает использование диска, но увеличивает нагрузку на ЦП.
- Сериализатор/десериализатор Avro вместо JSON требует предварительного определения схем, но повышает производительность и снижает потребление памяти.
4. Разделы (партиции)
Темы Kafka делятся на разделы, что обеспечивает параллельную обработку и масштабируемость. Сообщения в разделе упорядочены и неизменяемы.
5. Потребитель
Читает сообщения из разделов и отслеживает свою позицию с помощью смещения. Потребители могут сбрасывать смещения для повторной обработки старых сообщений. Потребители Kafka работают по модели опроса, то есть они постоянно запрашивают данные у брокера, а не брокер отправляет им данные.
6. Группа потребителей
Набор потребителей, которые работают вместе для обработки сообщений из темы. Kafka гарантирует, что один раздел потребляется только одним потребителем в группе, поддерживая порядок.
7. Управление смещением
Когда потребитель читает сообщение, он обновляет своё смещение — позицию последнего обработанного сообщения.
8. Брокер
Сервер Kafka, который хранит сообщения, назначает смещения и обрабатывает клиентские запросы. Несколько брокеров образуют кластер для масштабируемости и отказоустойчивости.
9. Zookeeper
Zookeeper управляет кластером: отслеживает брокеров, выбирает новый ведущий сервер при отказе и т.п. Однако более новые версии Kafka работают над устранением зависимости от Zookeeper.
Источник: https://dev.to/lovestaco/why-kafka-a-developer-friendly-guide-to-event-driven-architecture-4ekf
👍13
День 2228.
Почему Разработчики Должны Заботиться о Безопасности
Разрабатывает ли кто-нибудь ПО, в котором сбои не имеют последствий? Даже незначительные сбои ПО могут иметь далеко идущие последствия: компании теряют миллионы, а пользователи доверие, и всё из-за сбоев, которые можно было бы предотвратить. Вспомним Crowdstrike. Не должны ли все разработчики думать о безопасности и надёжности, даже при создании приложений, которые кажутся некритичными?
Однозначно да. Принятие принципов разработки ПО, ориентированных на безопасность, может помочь создавать более надёжные, заслуживающие доверия и устойчивые системы. Речь не об оверинжиниринге, а о принятии ответственности за то, что происходит, когда что-то неизбежно идёт не так.
1. Всё ПО следует считать высокорискованным
Каждый сбой имеет последствия. Где-то потеря активов или дохода, а где-то от этого могут зависеть жизни. Этот принцип означает признание того, что каждая система взаимодействует с пользователями, данными или процессами способами, сбои в которых могут иметь каскадные эффекты. Готовясь к сбоям, разработчики улучшают коммуникацию, проектируют с оглядкой на надёжность, и в итоге предоставляют системы, которым пользователи могут доверять.
2. Проектирование для неизбежного сбоя
Сбои неизбежны. Каждая система в итоге столкнётся с условием, для которого она явно не была разработана, и то, как она реагирует на это, определяет, вызовет ли сбой серьёзную проблему.
В критически важных системах множественные сбои могут происходить без потери функциональности или данных. Но не нужно заходить так далеко для повседневного ПО.
Например, при активно-пассивном проектировании систем активный компонент обрабатывает запросы, а резервный остаётся бездействующим. Если активный компонент выходит из строя, пассивный берёт на себя управление, сводя к минимуму время простоя. Прокси и балансировщики нагрузки распределяют трафик между несколькими экземплярами, гарантируя, что отказ в одном не сможет вывести из строя всю систему.
Распределённые системы также упрощают изоляцию и восстановление после сбоев, поскольку отдельные сервисы можно перезапускать или изменять, не влияя на другие.
Разработчики также могут вести непрерывный мониторинг для раннего обнаружения проблем. Чем быстрее вы можете обнаружить и диагностировать проблему, тем быстрее вы сможете её исправить.
Тестирование на отказ не менее важно. Такие практики, как хаос-инжиниринг, подразумевающие намеренное внесение сбоев в систему, помогают выявлять слабые места и обеспечивать корректное восстановление.
3. Изучение критически важных для безопасности практик
Отрасли, где безопасность критически важна, вкладывают значительные средства в упреждающую защиту. Защитное программирование является ключевой практикой: надёжная проверка ввода, обработка ошибок и подготовка к крайним случаям. Простая ошибка ввода может привести к сбою сервиса, если её не обработать должным образом. Создание систем с учётом этого гарантирует, что вы всегда будете предвидеть неожиданности.
Нормой должно быть строгое тестирование, а не только модульные тесты. Рассмотрите тестирование с внедрением неисправностей (потерянные пакеты, повреждённые данные или недоступные ресурсы), чтобы наблюдать, как реагирует система.
Постепенная деградация — ещё один принцип, который стоит принять. Если система выходит из строя, она должна это делать безопасным и понятным образом. Система онлайн-платежей может временно отключить обработку кредитных карт, но позволить пользователям сохранять товары в корзине. Сервис потокового видео может снизить качество воспроизведения вместо полной остановки. Пользователи должны иметь возможность продолжать работу с ограниченной функциональностью, а не сталкиваться с полными отключениями.
Хотя разработка ПО с учётом безопасности может показаться излишним для некритических приложений, даже упрощённые версии этих принципов могут привести к более надёжному и удобному для пользователя ПО.
Источник: https://stackoverflow.blog/2025/01/22/why-all-developers-should-adopt-a-safety-critical-mindset/
Почему Разработчики Должны Заботиться о Безопасности
Разрабатывает ли кто-нибудь ПО, в котором сбои не имеют последствий? Даже незначительные сбои ПО могут иметь далеко идущие последствия: компании теряют миллионы, а пользователи доверие, и всё из-за сбоев, которые можно было бы предотвратить. Вспомним Crowdstrike. Не должны ли все разработчики думать о безопасности и надёжности, даже при создании приложений, которые кажутся некритичными?
Однозначно да. Принятие принципов разработки ПО, ориентированных на безопасность, может помочь создавать более надёжные, заслуживающие доверия и устойчивые системы. Речь не об оверинжиниринге, а о принятии ответственности за то, что происходит, когда что-то неизбежно идёт не так.
1. Всё ПО следует считать высокорискованным
Каждый сбой имеет последствия. Где-то потеря активов или дохода, а где-то от этого могут зависеть жизни. Этот принцип означает признание того, что каждая система взаимодействует с пользователями, данными или процессами способами, сбои в которых могут иметь каскадные эффекты. Готовясь к сбоям, разработчики улучшают коммуникацию, проектируют с оглядкой на надёжность, и в итоге предоставляют системы, которым пользователи могут доверять.
2. Проектирование для неизбежного сбоя
Сбои неизбежны. Каждая система в итоге столкнётся с условием, для которого она явно не была разработана, и то, как она реагирует на это, определяет, вызовет ли сбой серьёзную проблему.
В критически важных системах множественные сбои могут происходить без потери функциональности или данных. Но не нужно заходить так далеко для повседневного ПО.
Например, при активно-пассивном проектировании систем активный компонент обрабатывает запросы, а резервный остаётся бездействующим. Если активный компонент выходит из строя, пассивный берёт на себя управление, сводя к минимуму время простоя. Прокси и балансировщики нагрузки распределяют трафик между несколькими экземплярами, гарантируя, что отказ в одном не сможет вывести из строя всю систему.
Распределённые системы также упрощают изоляцию и восстановление после сбоев, поскольку отдельные сервисы можно перезапускать или изменять, не влияя на другие.
Разработчики также могут вести непрерывный мониторинг для раннего обнаружения проблем. Чем быстрее вы можете обнаружить и диагностировать проблему, тем быстрее вы сможете её исправить.
Тестирование на отказ не менее важно. Такие практики, как хаос-инжиниринг, подразумевающие намеренное внесение сбоев в систему, помогают выявлять слабые места и обеспечивать корректное восстановление.
3. Изучение критически важных для безопасности практик
Отрасли, где безопасность критически важна, вкладывают значительные средства в упреждающую защиту. Защитное программирование является ключевой практикой: надёжная проверка ввода, обработка ошибок и подготовка к крайним случаям. Простая ошибка ввода может привести к сбою сервиса, если её не обработать должным образом. Создание систем с учётом этого гарантирует, что вы всегда будете предвидеть неожиданности.
Нормой должно быть строгое тестирование, а не только модульные тесты. Рассмотрите тестирование с внедрением неисправностей (потерянные пакеты, повреждённые данные или недоступные ресурсы), чтобы наблюдать, как реагирует система.
Постепенная деградация — ещё один принцип, который стоит принять. Если система выходит из строя, она должна это делать безопасным и понятным образом. Система онлайн-платежей может временно отключить обработку кредитных карт, но позволить пользователям сохранять товары в корзине. Сервис потокового видео может снизить качество воспроизведения вместо полной остановки. Пользователи должны иметь возможность продолжать работу с ограниченной функциональностью, а не сталкиваться с полными отключениями.
Хотя разработка ПО с учётом безопасности может показаться излишним для некритических приложений, даже упрощённые версии этих принципов могут привести к более надёжному и удобному для пользователя ПО.
Источник: https://stackoverflow.blog/2025/01/22/why-all-developers-should-adopt-a-safety-critical-mindset/
👍7
День 2229. #юмор
Сегодня порекомендую вам прекрасный канал Developer Timeline с пародиями на распространённые случаи из жизни разработчиков. Видео переозвучивают известные фильмы и сериалы. Из понравившихся мне:
- I Am The Documentation
- Pull Request With A Few Minor Changes
- First Day Of Programming
- Git Commit, Git Push and Leave the Building
- Developer Interviews In 2025 Be Like
Не то, чтоб уморительно смешно, но жизненно.
Сегодня порекомендую вам прекрасный канал Developer Timeline с пародиями на распространённые случаи из жизни разработчиков. Видео переозвучивают известные фильмы и сериалы. Из понравившихся мне:
- I Am The Documentation
- Pull Request With A Few Minor Changes
- First Day Of Programming
- Git Commit, Git Push and Leave the Building
- Developer Interviews In 2025 Be Like
Не то, чтоб уморительно смешно, но жизненно.
👍2
День 2230. #УрокиРазработки
Уроки 50 Лет Разработки ПО
Урок 43. Решая вопрос о качестве ПО, вы выбираете: платить немало сейчас или позже, но ещё больше
Если вы собрали требования, а на следующий день клиент позвонил и попросил кое-что изменить, это легко - достаточно обновить требование. Но если клиент позвонил через полгода, когда уже частично реализован дизайн и написан код – это гораздо дороже. У каждого изменения есть цена. Даже обсуждение возможности добавления функциональности или исправления ошибки, а затем решение не делать этого требуют времени. Стоимость исправления дефекта зависит от того, когда он был допущен в продукте и когда кто-то его исправил. Она тем больше, чем позднее дефект обнаруживается.
Порядок увеличения затрат во многом зависит от того, какой объём работы был выполнен для реализации ошибочного требования и как много теперь необходимо переделать. Исправить быстро найденную ошибку в коде почти ничего не стоит. Но если клиент звонит, чтобы сообщить об ошибке уже после релиза ПО, то её исправление обойдется намного дороже. Есть и другой важный аспект: негативное влияние на пользователей. Чем позднее обнаружится проблема, тем более широкий круг заинтересованных сторон она затронет.
Ранние действия по улучшению качества
1. Предотвращайте дефекты, а не исправляйте их
Деятельность по обеспечению качества в первую очередь направлена на предотвращение дефектов. Усовершенствованные процессы, лучшие технические приёмы, более опытные специалисты и немного больше времени на тщательное выполнение работы помогают предотвратить ошибки и избежать затрат на их исправление.
2. Выполняйте контроль качества раньше
На каждом этапе работы над ПО совершается микропоследовательность действий: определение требований, разработка дизайна и программирование. Устранение ошибок в требованиях максимально экономит время в будущем, поэтому используйте все имеющиеся инструменты для поиска ошибок в требованиях и проектах до того, как они превратятся в ошибочный код.
Смещение тестирования с его традиционного места в конце разработки на более ранние этапы даёт особенно сильный эффект. В числе возможных стратегий можно назвать разработку через тестирование, создание приёмочных тестов для конкретизации деталей требований и одновременное написание функциональных требований и соответствующих им тестов.
Разрабатывая тесты вскоре после определения требований, можно сразу находить ошибки как в требованиях, так и в тестах. Написание тестов бизнес-аналитиком в сотрудничестве с тестировщиком даёт положительный эффект, т.к. участвуют люди, смотрящие на одно и то же явление с разных точек зрения. Написание тестов в начале цикла разработки не увеличивает время разработки проекта, а просто перераспределяет его, перенося тестирование в точку, где оно обеспечивает наибольшее влияние на качество. Эти концептуальные тесты могут быть преобразованы в подробные тестовые сценарии и процедуры по мере разработки.
Инструменты статического и динамического анализа кода, помогут выявить многие проблемы гораздо быстрее, чем при просмотре вручную. А рецензенты-люди могут выявлять логические ошибки и упущения в коде, которые не обнаруживаются автоматическими инструментами.
3. Отслеживайте дефекты, чтобы понять их
Записывайте информацию о своих ошибках вместо того, чтобы просто исправлять их. Определяйте причины происхождения каждого дефекта, чтобы понять, какие типы ошибок возникают чаще всего. Вы не поняли, чего хочет клиент? Сделали неправильное предположение о системных компонентах или интерфейсах? Ошиблись при программировании? О запросе клиента узнали не все, кто должен был об нём знать?
Обратите внимание на действия в жизненном цикле, при выполнении которых возник каждый дефект, и на то, как он был обнаружен. Так можно рассчитать, сколько дефектов переходят с этапа, на котором они появились, на более поздние этапы разработки, увеличивая стоимость их исправления. Это покажет, какие практики обнаружения дефектов наиболее эффективны и где ещё можно улучшить контроль.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 6.
Уроки 50 Лет Разработки ПО
Урок 43. Решая вопрос о качестве ПО, вы выбираете: платить немало сейчас или позже, но ещё больше
Если вы собрали требования, а на следующий день клиент позвонил и попросил кое-что изменить, это легко - достаточно обновить требование. Но если клиент позвонил через полгода, когда уже частично реализован дизайн и написан код – это гораздо дороже. У каждого изменения есть цена. Даже обсуждение возможности добавления функциональности или исправления ошибки, а затем решение не делать этого требуют времени. Стоимость исправления дефекта зависит от того, когда он был допущен в продукте и когда кто-то его исправил. Она тем больше, чем позднее дефект обнаруживается.
Порядок увеличения затрат во многом зависит от того, какой объём работы был выполнен для реализации ошибочного требования и как много теперь необходимо переделать. Исправить быстро найденную ошибку в коде почти ничего не стоит. Но если клиент звонит, чтобы сообщить об ошибке уже после релиза ПО, то её исправление обойдется намного дороже. Есть и другой важный аспект: негативное влияние на пользователей. Чем позднее обнаружится проблема, тем более широкий круг заинтересованных сторон она затронет.
Ранние действия по улучшению качества
1. Предотвращайте дефекты, а не исправляйте их
Деятельность по обеспечению качества в первую очередь направлена на предотвращение дефектов. Усовершенствованные процессы, лучшие технические приёмы, более опытные специалисты и немного больше времени на тщательное выполнение работы помогают предотвратить ошибки и избежать затрат на их исправление.
2. Выполняйте контроль качества раньше
На каждом этапе работы над ПО совершается микропоследовательность действий: определение требований, разработка дизайна и программирование. Устранение ошибок в требованиях максимально экономит время в будущем, поэтому используйте все имеющиеся инструменты для поиска ошибок в требованиях и проектах до того, как они превратятся в ошибочный код.
Смещение тестирования с его традиционного места в конце разработки на более ранние этапы даёт особенно сильный эффект. В числе возможных стратегий можно назвать разработку через тестирование, создание приёмочных тестов для конкретизации деталей требований и одновременное написание функциональных требований и соответствующих им тестов.
Разрабатывая тесты вскоре после определения требований, можно сразу находить ошибки как в требованиях, так и в тестах. Написание тестов бизнес-аналитиком в сотрудничестве с тестировщиком даёт положительный эффект, т.к. участвуют люди, смотрящие на одно и то же явление с разных точек зрения. Написание тестов в начале цикла разработки не увеличивает время разработки проекта, а просто перераспределяет его, перенося тестирование в точку, где оно обеспечивает наибольшее влияние на качество. Эти концептуальные тесты могут быть преобразованы в подробные тестовые сценарии и процедуры по мере разработки.
Инструменты статического и динамического анализа кода, помогут выявить многие проблемы гораздо быстрее, чем при просмотре вручную. А рецензенты-люди могут выявлять логические ошибки и упущения в коде, которые не обнаруживаются автоматическими инструментами.
3. Отслеживайте дефекты, чтобы понять их
Записывайте информацию о своих ошибках вместо того, чтобы просто исправлять их. Определяйте причины происхождения каждого дефекта, чтобы понять, какие типы ошибок возникают чаще всего. Вы не поняли, чего хочет клиент? Сделали неправильное предположение о системных компонентах или интерфейсах? Ошиблись при программировании? О запросе клиента узнали не все, кто должен был об нём знать?
Обратите внимание на действия в жизненном цикле, при выполнении которых возник каждый дефект, и на то, как он был обнаружен. Так можно рассчитать, сколько дефектов переходят с этапа, на котором они появились, на более поздние этапы разработки, увеличивая стоимость их исправления. Это покажет, какие практики обнаружения дефектов наиболее эффективны и где ещё можно улучшить контроль.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 6.
👍8
Какой перевод слова production (environment) на русский язык вы считаете наиболее удачным (понятным)?
Anonymous Poll
16%
Производственная
7%
Продуктивная
13%
Продуктовая
50%
Продакшен
11%
Рабочая
2%
Другой (напишите в комментариях)
День 2231. #Безопасность
Атрибуты Безопасности Файлов Cookie
Один из самых распространённых способов, которым веб-браузеры используют cookie, — это аутентификация пользователя и сохранение сессии. Злоумышленники могут украсть или подделать cookie для получения доступа к аутентифицированным областям и существующим сессиям пользователя.
Существует 3 распространённых атаки с использованием cookie:
1. Атаки с использованием межсайтового скриптинга (XSS) и атаки типа «человек посередине» (MITM) часто используются для кражи файлов cookie.
2. Атаки с использованием межсайтовой подделки запросов (CSRF) используют способ обработки файлов cookie браузерами для выполнения вредоносных действий от имени аутентифицированных пользователей.
Спецификация протокола HTTP содержит несколько механизмов, которые разработчики могут использовать для снижения риска доступа злоумышленников к содержимому cookie с конфиденциальными данными, их повторного использования или подделки. Ниже перечислены атрибуты заголовка HTTP Set-Cookie, которые можно использовать для повышения безопасности файлов cookie.
1. Expire и Max-Age
Определяют срок действия cookie. Expire устанавливает абсолютную дату/время истечения срока действия (формат: weekday, DD-MM-YYYY hh:mm:ss GMT), а атрибут Max-Age - ограничение по времени с момента установки cookie. Если Expire и Max-Age не установлены, браузер обрабатывает cookie как сеансовый и удаляет его при закрытии браузера. Если установлены, сохраняет cookie как постоянный на стороне клиента и удаляет в соответствии со значениями Expire и Max-Age (в зависимости от того, что наступит раньше).
2. Secure
Указывает, что cookie может передаваться только с использованием HTTPS-соединений и никогда не отправляется в открытом виде. Браузер не будет отправлять Secure cookie с запросами HTTP.
Атрибут Secure предназначен для защиты от атак типа «человек посередине» (MITM). Однако он защищает только конфиденциальность файла cookie, а не его целостность. Злоумышленник не получит cookie с сервера через незашифрованное соединение, но всё равно может отправить поддельный cookie на сервер в виде обычного текста.
3. Domain
Объявляет домен, на который будет отправлен cookie (а также все поддомены). Если атрибут Domain не установлен, cookie будет отправлен только на исходный хост (без поддоменов). Поэтому наиболее безопасный способ — не устанавливать атрибут Domain, если это не необходимо.
4. Path
URL-путь, по которому будет отправлен cookie (включая все подпути). По умолчанию - / (все URL-пути на сервере).
5. HttpOnly
Введён для предотвращения атак XSS. Браузер будет отправлять cookie с этим атрибутом только в ответ на HTTP-запросы, т.е. к ним нельзя будет получить доступ из клиентского кода JavaScript. Однако атрибут HttpOnly не защищает cookie от перезаписи. Браузер может хранить только ограниченное количество файлов cookie для домена. Злоумышленник может использовать атаку переполнения хранилища cookie, тем самым удаляя исходный cookie из памяти браузера и добавляя cookie с тем же именем без атрибута HttpOnly.
6. SameSite
Предписывает веб-браузерам отправлять cookie по-разному в зависимости от того, как посетитель взаимодействует с сайтом, установившим cookie. Используется для защиты от атак CSRF. Может иметь одно из следующих значений:
-
-
-
Внимание: если атрибут SameSite не установлен, можно ожидать разного поведения браузеров и разных версий одного браузера.
См. также Cookie и Управление Сессиями
Источник: https://www.invicti.com/learn/cookie-security-flags/
Атрибуты Безопасности Файлов Cookie
Один из самых распространённых способов, которым веб-браузеры используют cookie, — это аутентификация пользователя и сохранение сессии. Злоумышленники могут украсть или подделать cookie для получения доступа к аутентифицированным областям и существующим сессиям пользователя.
Существует 3 распространённых атаки с использованием cookie:
1. Атаки с использованием межсайтового скриптинга (XSS) и атаки типа «человек посередине» (MITM) часто используются для кражи файлов cookie.
2. Атаки с использованием межсайтовой подделки запросов (CSRF) используют способ обработки файлов cookie браузерами для выполнения вредоносных действий от имени аутентифицированных пользователей.
Спецификация протокола HTTP содержит несколько механизмов, которые разработчики могут использовать для снижения риска доступа злоумышленников к содержимому cookie с конфиденциальными данными, их повторного использования или подделки. Ниже перечислены атрибуты заголовка HTTP Set-Cookie, которые можно использовать для повышения безопасности файлов cookie.
1. Expire и Max-Age
Определяют срок действия cookie. Expire устанавливает абсолютную дату/время истечения срока действия (формат: weekday, DD-MM-YYYY hh:mm:ss GMT), а атрибут Max-Age - ограничение по времени с момента установки cookie. Если Expire и Max-Age не установлены, браузер обрабатывает cookie как сеансовый и удаляет его при закрытии браузера. Если установлены, сохраняет cookie как постоянный на стороне клиента и удаляет в соответствии со значениями Expire и Max-Age (в зависимости от того, что наступит раньше).
2. Secure
Указывает, что cookie может передаваться только с использованием HTTPS-соединений и никогда не отправляется в открытом виде. Браузер не будет отправлять Secure cookie с запросами HTTP.
Атрибут Secure предназначен для защиты от атак типа «человек посередине» (MITM). Однако он защищает только конфиденциальность файла cookie, а не его целостность. Злоумышленник не получит cookie с сервера через незашифрованное соединение, но всё равно может отправить поддельный cookie на сервер в виде обычного текста.
3. Domain
Объявляет домен, на который будет отправлен cookie (а также все поддомены). Если атрибут Domain не установлен, cookie будет отправлен только на исходный хост (без поддоменов). Поэтому наиболее безопасный способ — не устанавливать атрибут Domain, если это не необходимо.
4. Path
URL-путь, по которому будет отправлен cookie (включая все подпути). По умолчанию - / (все URL-пути на сервере).
5. HttpOnly
Введён для предотвращения атак XSS. Браузер будет отправлять cookie с этим атрибутом только в ответ на HTTP-запросы, т.е. к ним нельзя будет получить доступ из клиентского кода JavaScript. Однако атрибут HttpOnly не защищает cookie от перезаписи. Браузер может хранить только ограниченное количество файлов cookie для домена. Злоумышленник может использовать атаку переполнения хранилища cookie, тем самым удаляя исходный cookie из памяти браузера и добавляя cookie с тем же именем без атрибута HttpOnly.
6. SameSite
Предписывает веб-браузерам отправлять cookie по-разному в зависимости от того, как посетитель взаимодействует с сайтом, установившим cookie. Используется для защиты от атак CSRF. Может иметь одно из следующих значений:
-
SameSite=Strict
: cookie отправляется только, если вы в данный момент находитесь на сайте, который установил cookie. Если вы переходите с другого сайта (например, из результатов поиска в Google), такой cookie не отправляется с первым запросом.-
SameSite=Lax
: файл куки отправляется с GET-запросами верхнего уровня, но не отправляется для встроенного контента (рисунки, CSS, JS).-
SameSite=None
: ограничений нет.Внимание: если атрибут SameSite не установлен, можно ожидать разного поведения браузеров и разных версий одного браузера.
См. также Cookie и Управление Сессиями
Источник: https://www.invicti.com/learn/cookie-security-flags/
👍15
День 2232. #ЧтоНовенького
Новые Функции Отладки в Visual Studio 17.13
В VS 17.13 добавили набор функций отладки и профилирования, предназначенных для ускорения устранения неполадок, делая процесс более эффективным. Благодаря функциям на основе ИИ анализ переменных и проверка данных стали более интеллектуальными и интуитивно понятными, а проблемы стало проще выявлять и отлаживать.
1. Более интеллектуальный анализ исключений и переменных
Анализ исключений и переменных с помощью GitHub Copilot теперь использует контекст вашего проекта, чтобы находить и предлагать не только объяснение найденной ошибки, но и наиболее релевантный код для её исправления.
Благодаря более чётким контекстно-зависимым решениям эта функция поможет вам быстрее выявить первопричину проблем, сделать рабочий процесс отладки более рациональным и обеспечить большую общую точность при отладке ошибок. См. картинку 1.
2. Улучшенные редактируемые выражения в визуализаторе IEnumerable
Визуализатор IEnumerable теперь имеет встроенный чат GitHub Copilot, позволяющий уточнять редактируемые выражения с помощью естественного языка. Нажмите на кнопку Continue in Chat (Продолжить в Чате), сообщите Copilot, что вы хотели бы изменить, и получите сгенерированный ИИ запрос LINQ, включая подсветку синтаксиса для облегчения чтения. См. картинку 2.
3. Многопроцессный анализ использования CPU
Инструмент использования CPU в профилировщике Visual Studio теперь поддерживает многопроцессный анализ, при этом графики производительности отображаются разными цветами для каждого процесса. Графики отображаются в виде диаграмм с перекрывающимися областями. Вы также можете фильтровать процессы с помощью раскрывающегося списка в левом верхнем углу. См. картинку 3.
Это позволяет легко филировать и изолировать использование CPU по процессам в одном сеансе, упрощая отладку производительности многопроцессных приложений.
4. Помощь в поиске проблем перед коммитом в Git
Новая функция (в VS 17.14 preview 1) на базе GitHub Copilot представляет ревью изменений кода перед коммитом. Это может помочь выявить проблемы с производительностью и безопасностью на ранней стадии, гарантируя вам более высокое качество кодовой базы.
Чтобы использовать эту функцию, убедитесь, что ваша подписка GitHub Copilot активна и включена в Visual Studio. Включите необходимые флаги функций: Tools > Options > Preview Features > Pull Request Add Comment (Инструменты > Параметры > Функции предварительной версии > Комментарии к пул-реквестам) и Tools > Options > GitHub > Copilot > Source Control Integration > Enable Git preview features (Инструменты > Параметры > GitHub > Copilot > Интеграция с системой управления исходным кодом > Включить превью функции для Git). Тогда в окне Git Changes в заголовке изменений вы увидите значок чата. При нажатии на него GitHub Copilot проведёт обзор ваших локальных изменений и представит предложения. См. картинку 4.
Как и со всеми функциями на базе ИИ, вам нужно будет просмотреть предложения Copilot на точность, что можно сделать прямо в файле кода. Вы можете перемещаться между комментариями или сворачивать их, используя кнопки в заголовке комментария.
Источники:
- https://devblogs.microsoft.com/visualstudio/new-debugging-and-profiling-features-in-visual-studio-v17-13/
- https://devblogs.microsoft.com/visualstudio/catch-issues-before-you-commit-to-git/
Новые Функции Отладки в Visual Studio 17.13
В VS 17.13 добавили набор функций отладки и профилирования, предназначенных для ускорения устранения неполадок, делая процесс более эффективным. Благодаря функциям на основе ИИ анализ переменных и проверка данных стали более интеллектуальными и интуитивно понятными, а проблемы стало проще выявлять и отлаживать.
1. Более интеллектуальный анализ исключений и переменных
Анализ исключений и переменных с помощью GitHub Copilot теперь использует контекст вашего проекта, чтобы находить и предлагать не только объяснение найденной ошибки, но и наиболее релевантный код для её исправления.
Благодаря более чётким контекстно-зависимым решениям эта функция поможет вам быстрее выявить первопричину проблем, сделать рабочий процесс отладки более рациональным и обеспечить большую общую точность при отладке ошибок. См. картинку 1.
2. Улучшенные редактируемые выражения в визуализаторе IEnumerable
Визуализатор IEnumerable теперь имеет встроенный чат GitHub Copilot, позволяющий уточнять редактируемые выражения с помощью естественного языка. Нажмите на кнопку Continue in Chat (Продолжить в Чате), сообщите Copilot, что вы хотели бы изменить, и получите сгенерированный ИИ запрос LINQ, включая подсветку синтаксиса для облегчения чтения. См. картинку 2.
3. Многопроцессный анализ использования CPU
Инструмент использования CPU в профилировщике Visual Studio теперь поддерживает многопроцессный анализ, при этом графики производительности отображаются разными цветами для каждого процесса. Графики отображаются в виде диаграмм с перекрывающимися областями. Вы также можете фильтровать процессы с помощью раскрывающегося списка в левом верхнем углу. См. картинку 3.
Это позволяет легко филировать и изолировать использование CPU по процессам в одном сеансе, упрощая отладку производительности многопроцессных приложений.
4. Помощь в поиске проблем перед коммитом в Git
Новая функция (в VS 17.14 preview 1) на базе GitHub Copilot представляет ревью изменений кода перед коммитом. Это может помочь выявить проблемы с производительностью и безопасностью на ранней стадии, гарантируя вам более высокое качество кодовой базы.
Чтобы использовать эту функцию, убедитесь, что ваша подписка GitHub Copilot активна и включена в Visual Studio. Включите необходимые флаги функций: Tools > Options > Preview Features > Pull Request Add Comment (Инструменты > Параметры > Функции предварительной версии > Комментарии к пул-реквестам) и Tools > Options > GitHub > Copilot > Source Control Integration > Enable Git preview features (Инструменты > Параметры > GitHub > Copilot > Интеграция с системой управления исходным кодом > Включить превью функции для Git). Тогда в окне Git Changes в заголовке изменений вы увидите значок чата. При нажатии на него GitHub Copilot проведёт обзор ваших локальных изменений и представит предложения. См. картинку 4.
Как и со всеми функциями на базе ИИ, вам нужно будет просмотреть предложения Copilot на точность, что можно сделать прямо в файле кода. Вы можете перемещаться между комментариями или сворачивать их, используя кнопки в заголовке комментария.
Источники:
- https://devblogs.microsoft.com/visualstudio/new-debugging-and-profiling-features-in-visual-studio-v17-13/
- https://devblogs.microsoft.com/visualstudio/catch-issues-before-you-commit-to-git/
👍11👎2
День 2233. #ЗаметкиНаПолях
Перебираем Элементы ConcurrentDictionary
Существует несколько способов итерации по ConcurrentDictionary<TKey, TValue> в .NET. Вы можете использовать цикл foreach или свойства Keys и Values. Оба метода дают разные результаты, и вам следует выбрать тот, который лучше всего соответствует вашим потребностям.
1. Использование цикла foreach
Цикл foreach лениво выполняет итерацию по парам ключ-значение в ConcurrentDictionary. Это означает, что цикл будет извлекать следующую пару ключ-значение только тогда, когда это необходимо. Кроме того, он перечисляет «живые» данные. Т.е., если вы добавите элемент во время итерации по словарю, цикл foreach может вернуть его*.
Ещё один интересный момент заключается в том, что перечисление не блокирует словарь, поэтому не влияет на производительность.
2. Использование свойств Keys и Values
Свойства Keys и Values возвращают снимок ключей и значений в словаре. Это означает, что коллекция, возвращаемая этими свойствами, является копией ключей и значений на момент вызова. Таким образом, если вы добавляете элемент во время итерации по словарю, свойства Keys и Values не вернут его. Кроме того, свойства Keys и Values блокируют словарь на время создания снимка. Это может повлиять на производительность, если словарь большой:
Источник: https://www.meziantou.net/how-to-iterate-on-a-concurrentdictionary-foreach-vs-keys-values.htm
Перебираем Элементы ConcurrentDictionary
Существует несколько способов итерации по ConcurrentDictionary<TKey, TValue> в .NET. Вы можете использовать цикл foreach или свойства Keys и Values. Оба метода дают разные результаты, и вам следует выбрать тот, который лучше всего соответствует вашим потребностям.
1. Использование цикла foreach
Цикл foreach лениво выполняет итерацию по парам ключ-значение в ConcurrentDictionary. Это означает, что цикл будет извлекать следующую пару ключ-значение только тогда, когда это необходимо. Кроме того, он перечисляет «живые» данные. Т.е., если вы добавите элемент во время итерации по словарю, цикл foreach может вернуть его*.
* Из документации: Перечислитель, возвращаемый из словаря, можно безопасно использовать одновременно с чтением и записью в словарь, однако он не представляет моментальный снимок словаря. Содержимое, представленное через перечислитель, может содержать изменения, внесенные в словарь после вызова GetEnumerator.
Ещё один интересный момент заключается в том, что перечисление не блокирует словарь, поэтому не влияет на производительность.
var dict = new ConcurrentDictionary<int, string>();
…
foreach (var pair in dict)
{
Console.WriteLine($"{pair.Key}: {pair.Value}");
}
2. Использование свойств Keys и Values
Свойства Keys и Values возвращают снимок ключей и значений в словаре. Это означает, что коллекция, возвращаемая этими свойствами, является копией ключей и значений на момент вызова. Таким образом, если вы добавляете элемент во время итерации по словарю, свойства Keys и Values не вернут его. Кроме того, свойства Keys и Values блокируют словарь на время создания снимка. Это может повлиять на производительность, если словарь большой:
var dict = new ConcurrentDictionary<int, string>();
…
foreach (var key in dict.Keys)
{
Console.WriteLine($"Key: {key}");
}
Источник: https://www.meziantou.net/how-to-iterate-on-a-concurrentdictionary-foreach-vs-keys-values.htm
👍36
День 2234. #BestPractices
Разбирайте, а не Валидируйте
Во многих приложениях валидация используется для определения того, соответствует ли заданная структура данных или объект определённым требованиям. Однако она не изменяет (не должна изменять) рассматриваемый объект, т.е. любое изменение в дальнейшем может сделать валидацию недействительной. Напротив, разбор (парсинг) менее структурированного объекта и создание из него более структурированного — это односторонняя операция, которая приводит к более полезным структурам данных.
Валидация
Валидация — это метод, действующий в определённый момент времени, который обычно возвращает true или false (или вместе с false - список причин, по которым он вернул false). Обычно он не имеет и не должен иметь никаких побочных эффектов, таких как мутация проверяемого объекта. Если структура данных или объект передаются между процедурами в приложении, то система, скорее всего, не сможет предполагать только на основе типа, что объект остаётся валидным по мере перемещения из одного контекста в другой. Таким образом, вы часто будете сталкиваться с проверкой, происходящей в нескольких точках в приложении даже для одного и того же экземпляра переменной или структуры.
Неизменяемые типы, конечно, помогают и могут быть проверены только один раз, а затем подразумеваться валидными, но только если проверка происходит как часть их построения. То есть типы, которые способны обеспечивать инварианты дизайна как часть их построения и которые являются неизменяемыми, могут считаться в системе валидными везде, где они появляются.
Парсинг
Процесс преобразования менее ограниченных типов в более ограниченные типов (или выдачи исключения, если это невозможно сделать) называется парсингом. Он добавляет дополнительные ограничения и, таким образом, уменьшает общий диапазон возможных значений, которые может представлять результирующий тип. Например:
Входная строка может быть относительно короткой последовательностью цифр (возможно, с префиксом -). Если это что-то другое, это всё ещё валидная строка, но это не валидный int, т.е. Parse() завершится ошибкой с исключением. Если приложению требуется числовое значение для использования в определённых методах или функциях, гораздо лучше преобразовать входную строку в целочисленное значение и затем передать его, чем передавать строку везде и каждый раз проверять, может ли она представлять целое число.
Парсеры и эту практику можно использовать совместно с неизменяемыми объектами. Принимая менее структурированные примитивные данные и разбирая их в объекты-значения, ваше ПО будет менее подвержено ошибкам, и вам придётся отслеживать меньше переменных в своей голове.
DateTime как пример
Представьте, что DateTime не существует, а приложению нужен способ представления значений даты и времени с точностью до секунды. Вы можете передать строку, которую нужно будет разобрать везде, где она используется как значение даты и/или времени. Очевидно, что в идеале вы должны выполнить операцию парсинга один раз, после чего у вас будет нестроковый тип, представляющий значение даты и времени.
Альтернативно, у вас могут быть методы со списками аргументов, такими как (int year, int month, int day, int hour, int minute, int second). Шесть целочисленных значений, каждое с отдельными допустимыми диапазонами. Можно выполнять проверку этих 6 значений в таком методе, прежде чем приступить к его фактической логике. Такая массированная проверка имеет тенденцию загромождать код и скрывать реальную работу, а также часто пропускать проверку некоторых входных данных в некоторых контекстах.
Прелесть типа DateTime в том, что разработчики могут быть уверены, что он всегда валиден. В этом смысл парсинга — создать более ограниченный тип более высокого уровня, который не требует проверки, поскольку он не может быть невалидным. Использование правильных типов вместо одержимости примитивами упростит написание правильных методов.
Источник: https://deviq.com/practices/parse-dont-validate
Разбирайте, а не Валидируйте
Во многих приложениях валидация используется для определения того, соответствует ли заданная структура данных или объект определённым требованиям. Однако она не изменяет (не должна изменять) рассматриваемый объект, т.е. любое изменение в дальнейшем может сделать валидацию недействительной. Напротив, разбор (парсинг) менее структурированного объекта и создание из него более структурированного — это односторонняя операция, которая приводит к более полезным структурам данных.
Валидация
Валидация — это метод, действующий в определённый момент времени, который обычно возвращает true или false (или вместе с false - список причин, по которым он вернул false). Обычно он не имеет и не должен иметь никаких побочных эффектов, таких как мутация проверяемого объекта. Если структура данных или объект передаются между процедурами в приложении, то система, скорее всего, не сможет предполагать только на основе типа, что объект остаётся валидным по мере перемещения из одного контекста в другой. Таким образом, вы часто будете сталкиваться с проверкой, происходящей в нескольких точках в приложении даже для одного и того же экземпляра переменной или структуры.
Неизменяемые типы, конечно, помогают и могут быть проверены только один раз, а затем подразумеваться валидными, но только если проверка происходит как часть их построения. То есть типы, которые способны обеспечивать инварианты дизайна как часть их построения и которые являются неизменяемыми, могут считаться в системе валидными везде, где они появляются.
Парсинг
Процесс преобразования менее ограниченных типов в более ограниченные типов (или выдачи исключения, если это невозможно сделать) называется парсингом. Он добавляет дополнительные ограничения и, таким образом, уменьшает общий диапазон возможных значений, которые может представлять результирующий тип. Например:
int.Parse(string input);
Входная строка может быть относительно короткой последовательностью цифр (возможно, с префиксом -). Если это что-то другое, это всё ещё валидная строка, но это не валидный int, т.е. Parse() завершится ошибкой с исключением. Если приложению требуется числовое значение для использования в определённых методах или функциях, гораздо лучше преобразовать входную строку в целочисленное значение и затем передать его, чем передавать строку везде и каждый раз проверять, может ли она представлять целое число.
Парсеры и эту практику можно использовать совместно с неизменяемыми объектами. Принимая менее структурированные примитивные данные и разбирая их в объекты-значения, ваше ПО будет менее подвержено ошибкам, и вам придётся отслеживать меньше переменных в своей голове.
DateTime как пример
Представьте, что DateTime не существует, а приложению нужен способ представления значений даты и времени с точностью до секунды. Вы можете передать строку, которую нужно будет разобрать везде, где она используется как значение даты и/или времени. Очевидно, что в идеале вы должны выполнить операцию парсинга один раз, после чего у вас будет нестроковый тип, представляющий значение даты и времени.
Альтернативно, у вас могут быть методы со списками аргументов, такими как (int year, int month, int day, int hour, int minute, int second). Шесть целочисленных значений, каждое с отдельными допустимыми диапазонами. Можно выполнять проверку этих 6 значений в таком методе, прежде чем приступить к его фактической логике. Такая массированная проверка имеет тенденцию загромождать код и скрывать реальную работу, а также часто пропускать проверку некоторых входных данных в некоторых контекстах.
Прелесть типа DateTime в том, что разработчики могут быть уверены, что он всегда валиден. В этом смысл парсинга — создать более ограниченный тип более высокого уровня, который не требует проверки, поскольку он не может быть невалидным. Использование правильных типов вместо одержимости примитивами упростит написание правильных методов.
Источник: https://deviq.com/practices/parse-dont-validate
👍21
День 2235. #Карьера
Ежедневная Практика Лучше Учёбы по Выходным
В мире разработки ПО постоянно появляются новые фреймворки, языки и инструменты, и велик соблазн изучить новинку за выходные или на курсе, чтобы поддерживать знания актуальными. Но секрет освоения разработки ПО не в марафонских учебных сессиях. Всё гораздо проще: дело в постоянстве.
Обучение по выходным или марафоны кодирования могут показаться продуктивными в данный момент, но они часто приводят к снижению отдачи. Вот причины:
1. Когнитивная перегрузка: попытка усвоить слишком много информации за короткий промежуток времени перегружает мозг, затрудняя эффективное сохранение и применение знаний.
2. Недостаток подкрепления: без постоянной практики концепции, которые вы изучаете за выходные, быстро забываются. Периодическое повторение гораздо эффективнее для долгосрочного запоминания.
3. Риск выгорания: интенсивные сеансы обучения могут привести к усталости, снижая мотивацию продолжать обучение в последующие дни или недели.
Напротив, ежедневная практика — даже всего 30 минут — создаёт устойчивую привычку и накопление знаний.
Правило 1% улучшения
Концепция, популяризированная Джеймсом Клиром в его книге «Атомные привычки». Небольшие, постепенные улучшения накапливаются со временем. Если вы улучшаетесь всего на 1% каждый день, то к концу года вы станете в 37 раз лучше.
Применительно к разработке это означает:
- Написание небольшого фрагмента кода каждый день.
- Решение одной проблемы кодирования ежедневно.
- Обзор новой концепции или отладка небольшой проблемы.
Почему это работает
1. Развивается «мышечная память» для кодирования
Как спортсменам, программным инженерам нужна регулярная практика, чтобы отточить свои навыки. Ежедневное написание кода помогает усвоить синтаксис, шаблоны и лучшие практики, делая вас быстрее и эффективнее.
2. Улучшаются навыки решения проблем
Решение проблем лежит в основе разработки ПО. Ежедневная практика подвергает вас различным испытаниям, помогая разработать набор стратегий и методов. Со временем вы обнаружите, что легче справляетесь со сложными проблемами.
3. Поощряется непрерывное обучение
Индустрия развивается быстро, и постоянное обучение гарантирует, что вы останетесь в тренде. Ежедневно выделяя время на изучение новых технологий или совершенствование имеющихся навыков, вы создаёте привычку к постоянному совершенствованию.
4. Уменьшается прокрастинация
Когда обучение кажется огромной задачей, его хочется отложить. Но выделить всего 15–30 минут в день проще. Это помогает преодолеть прокрастинацию и выработать дисциплину.
Как применять правило 1%
1. Установите ежедневную цель кодирования
Написать небольшой фрагмент кода, решить один алгоритм или отладить одну проблему в день. Используйте такие платформы, как LeetCode, HackerRank или Codewars, чтобы находить небольшие задачи.
2. Работа над сторонними проектами
Это отличный способ применить полученные знания в реальном контексте. Уделяйте немного времени каждый день созданию или улучшению проекта.
3. Обзор и рефакторинг кода
Уделяйте несколько минут каждый день обзору собственного кода или проектов с открытым кодом. Ищите способы улучшить читаемость, эффективность или структуру.
4. Изучайте небольшими порциями
Вместо того, чтобы пытаться освоить весь фреймворк за один присест, разбейте его на более мелкие темы.
5. Отслеживайте прогресс
Используйте журнал или приложение для отслеживания своей ежедневной деятельности по кодированию. Размышления о своём прогрессе укрепляют привычку и поддерживают мотивацию.
Последовательность в разработке ПО подобна сложным процентам. Сначала улучшения могут казаться незначительными, но со временем они накапливаются и выливаются в большой результат.
Источник: https://dev.to/jps27cse/the-role-of-consistency-in-software-engineering-why-daily-practice-beats-weekend-learning-36b9
Ежедневная Практика Лучше Учёбы по Выходным
В мире разработки ПО постоянно появляются новые фреймворки, языки и инструменты, и велик соблазн изучить новинку за выходные или на курсе, чтобы поддерживать знания актуальными. Но секрет освоения разработки ПО не в марафонских учебных сессиях. Всё гораздо проще: дело в постоянстве.
Обучение по выходным или марафоны кодирования могут показаться продуктивными в данный момент, но они часто приводят к снижению отдачи. Вот причины:
1. Когнитивная перегрузка: попытка усвоить слишком много информации за короткий промежуток времени перегружает мозг, затрудняя эффективное сохранение и применение знаний.
2. Недостаток подкрепления: без постоянной практики концепции, которые вы изучаете за выходные, быстро забываются. Периодическое повторение гораздо эффективнее для долгосрочного запоминания.
3. Риск выгорания: интенсивные сеансы обучения могут привести к усталости, снижая мотивацию продолжать обучение в последующие дни или недели.
Напротив, ежедневная практика — даже всего 30 минут — создаёт устойчивую привычку и накопление знаний.
Правило 1% улучшения
Концепция, популяризированная Джеймсом Клиром в его книге «Атомные привычки». Небольшие, постепенные улучшения накапливаются со временем. Если вы улучшаетесь всего на 1% каждый день, то к концу года вы станете в 37 раз лучше.
Применительно к разработке это означает:
- Написание небольшого фрагмента кода каждый день.
- Решение одной проблемы кодирования ежедневно.
- Обзор новой концепции или отладка небольшой проблемы.
Почему это работает
1. Развивается «мышечная память» для кодирования
Как спортсменам, программным инженерам нужна регулярная практика, чтобы отточить свои навыки. Ежедневное написание кода помогает усвоить синтаксис, шаблоны и лучшие практики, делая вас быстрее и эффективнее.
2. Улучшаются навыки решения проблем
Решение проблем лежит в основе разработки ПО. Ежедневная практика подвергает вас различным испытаниям, помогая разработать набор стратегий и методов. Со временем вы обнаружите, что легче справляетесь со сложными проблемами.
3. Поощряется непрерывное обучение
Индустрия развивается быстро, и постоянное обучение гарантирует, что вы останетесь в тренде. Ежедневно выделяя время на изучение новых технологий или совершенствование имеющихся навыков, вы создаёте привычку к постоянному совершенствованию.
4. Уменьшается прокрастинация
Когда обучение кажется огромной задачей, его хочется отложить. Но выделить всего 15–30 минут в день проще. Это помогает преодолеть прокрастинацию и выработать дисциплину.
Как применять правило 1%
1. Установите ежедневную цель кодирования
Написать небольшой фрагмент кода, решить один алгоритм или отладить одну проблему в день. Используйте такие платформы, как LeetCode, HackerRank или Codewars, чтобы находить небольшие задачи.
2. Работа над сторонними проектами
Это отличный способ применить полученные знания в реальном контексте. Уделяйте немного времени каждый день созданию или улучшению проекта.
3. Обзор и рефакторинг кода
Уделяйте несколько минут каждый день обзору собственного кода или проектов с открытым кодом. Ищите способы улучшить читаемость, эффективность или структуру.
4. Изучайте небольшими порциями
Вместо того, чтобы пытаться освоить весь фреймворк за один присест, разбейте его на более мелкие темы.
5. Отслеживайте прогресс
Используйте журнал или приложение для отслеживания своей ежедневной деятельности по кодированию. Размышления о своём прогрессе укрепляют привычку и поддерживают мотивацию.
Последовательность в разработке ПО подобна сложным процентам. Сначала улучшения могут казаться незначительными, но со временем они накапливаются и выливаются в большой результат.
Источник: https://dev.to/jps27cse/the-role-of-consistency-in-software-engineering-why-daily-practice-beats-weekend-learning-36b9
👍31
День 2236. #УрокиРазработки
Уроки 50 Лет Разработки ПО
Урок 44. Высокое качество естественным образом ведет к повышению продуктивности. Начало
Разработчики ПО хотели бы работать более продуктивно. Но этому могут мешать многие факторы, и проблемы с качеством — главный. Команды планируют выполнить установленный объём работы за определённое время, но затем им приходится устранять проблемы, обнаруженные в завершённом проекте, или выделять время на исправление работающей системы. Один из способов повысить продуктивность — создавать качественное ПО с самого начала.
Существуют два основных вида доработок ПО: исправление дефектов и погашение технического долга. Ранее мы рассмотрели, как со временем растут затраты на исправление дефектов. Точно так же чем дольше в коде сохраняются недостатки, тем больше накапливается технического долга и тем больше работы требуется для улучшения проектного решения. Рефакторинг упрощает поддержку и расширение кода, но иногда код необходимо рефакторить лишь потому, что он был создан в спешке на основе далеко не идеального проекта. Объёмная непредвиденная доработка — пустая трата времени, которая отвлекает разработчиков от создания дополнительной ценности для клиентов.
Слишком часто организации безоговорочно воспринимают рефакторинг как неотъемлемую часть разработки. Конечно, определённая доработка ПО неизбежна. Это обусловлено природой умственного труда, несовершенством человеческого общения и нашей неспособностью ясно видеть будущее. Лучше переделать проектное решение, чтобы добавить неожиданные новые функции, чем перепроектировать систему ради потенциального роста, которого никогда не будет. Тем не менее каждая команда должна стараться минимизировать переделки, которых можно избежать, улучшая качество своей работы с самого начала.
Проектные группы не всегда учитывают вероятность переделки при планировании. Даже если их оценки точны в отношении разработки, они окажутся весьма далекими от реальности, как только потребуются переделки. Эта проблема возникает в проектах, где не выделяется времени на исправление ошибок, обнаруженных во время мероприятий по контролю качества, таких как тестирование или рецензирование. Планируйте доработку в виде отдельных задач проекта, а не прячьте её внутри задач по исправлению дефектов. Обеспечив видимость трудозатрат на доработку, вы сделаете первый шаг к их сокращению.
Организации, подсчитывающие, сколько сил и средств уходит на доработку ПО, могут получить пугающие цифры. Различные исследования показывают, что это может быть от 40 до 50% времени. Только подумайте, как подскочила бы продуктивность вашей команды, если бы они могли дополнительно тратить треть своего времени для разработки чего-то нового!
Если вы фиксируете некие показатели, характеризующие затраты на разработку, то постарайтесь отделить затраты на поиск дефектов от затрат на их устранение. Узнайте, сколько времени вы тратите на доработку, когда и почему. Эти данные раскрывают широкие возможности для повышения продуктивности. Спойлер: до 85% затрат на доработку приходится на дефекты в требованиях. Наличие неких исходных данных о затратах на доработку позволит вам наметить цели для улучшения и увидеть, снижают ли более совершенные процессы и методы разработки необходимость в доработках.
Окончание следует…
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 6.
Уроки 50 Лет Разработки ПО
Урок 44. Высокое качество естественным образом ведет к повышению продуктивности. Начало
Разработчики ПО хотели бы работать более продуктивно. Но этому могут мешать многие факторы, и проблемы с качеством — главный. Команды планируют выполнить установленный объём работы за определённое время, но затем им приходится устранять проблемы, обнаруженные в завершённом проекте, или выделять время на исправление работающей системы. Один из способов повысить продуктивность — создавать качественное ПО с самого начала.
Существуют два основных вида доработок ПО: исправление дефектов и погашение технического долга. Ранее мы рассмотрели, как со временем растут затраты на исправление дефектов. Точно так же чем дольше в коде сохраняются недостатки, тем больше накапливается технического долга и тем больше работы требуется для улучшения проектного решения. Рефакторинг упрощает поддержку и расширение кода, но иногда код необходимо рефакторить лишь потому, что он был создан в спешке на основе далеко не идеального проекта. Объёмная непредвиденная доработка — пустая трата времени, которая отвлекает разработчиков от создания дополнительной ценности для клиентов.
Слишком часто организации безоговорочно воспринимают рефакторинг как неотъемлемую часть разработки. Конечно, определённая доработка ПО неизбежна. Это обусловлено природой умственного труда, несовершенством человеческого общения и нашей неспособностью ясно видеть будущее. Лучше переделать проектное решение, чтобы добавить неожиданные новые функции, чем перепроектировать систему ради потенциального роста, которого никогда не будет. Тем не менее каждая команда должна стараться минимизировать переделки, которых можно избежать, улучшая качество своей работы с самого начала.
Проектные группы не всегда учитывают вероятность переделки при планировании. Даже если их оценки точны в отношении разработки, они окажутся весьма далекими от реальности, как только потребуются переделки. Эта проблема возникает в проектах, где не выделяется времени на исправление ошибок, обнаруженных во время мероприятий по контролю качества, таких как тестирование или рецензирование. Планируйте доработку в виде отдельных задач проекта, а не прячьте её внутри задач по исправлению дефектов. Обеспечив видимость трудозатрат на доработку, вы сделаете первый шаг к их сокращению.
Организации, подсчитывающие, сколько сил и средств уходит на доработку ПО, могут получить пугающие цифры. Различные исследования показывают, что это может быть от 40 до 50% времени. Только подумайте, как подскочила бы продуктивность вашей команды, если бы они могли дополнительно тратить треть своего времени для разработки чего-то нового!
Если вы фиксируете некие показатели, характеризующие затраты на разработку, то постарайтесь отделить затраты на поиск дефектов от затрат на их устранение. Узнайте, сколько времени вы тратите на доработку, когда и почему. Эти данные раскрывают широкие возможности для повышения продуктивности. Спойлер: до 85% затрат на доработку приходится на дефекты в требованиях. Наличие неких исходных данных о затратах на доработку позволит вам наметить цели для улучшения и увидеть, снижают ли более совершенные процессы и методы разработки необходимость в доработках.
Окончание следует…
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 6.
👍10
HTML Embed Code: