День 1950. #Оффтоп
.NET Rocks со Скотом Хансельманом
Олды тут? Если вдруг вам нечем заняться в первое воскресенье лета, послушайте юбилейный 1900й выпуск подкаста .NET Rocks с одним из моих любимых популяризаторов программирования вообще и .NET в частности, Скотом Хансельманом.
Три «старичка» в программировании в рамках конференции Microsoft Build весело поболтали о былых временах, о том, как быть «престарелым» (ближе к 50) программистом, идеях и истоках всех подкастов и популярности в соцсетях, а также о том, что для Скотта важно сегодня. Во второй половине Карл Фрэнклин устраивает для Скотта викторину, вспомнит ли он, что он отвечал на вопросы ведущих подкаста 20-лет назад!
И множество других замечательных историй о различных конференциях, подкастах и других мероприятиях, а также о том, чему научились в процессе.
.NET Rocks со Скотом Хансельманом
Олды тут? Если вдруг вам нечем заняться в первое воскресенье лета, послушайте юбилейный 1900й выпуск подкаста .NET Rocks с одним из моих любимых популяризаторов программирования вообще и .NET в частности, Скотом Хансельманом.
Три «старичка» в программировании в рамках конференции Microsoft Build весело поболтали о былых временах, о том, как быть «престарелым» (ближе к 50) программистом, идеях и истоках всех подкастов и популярности в соцсетях, а также о том, что для Скотта важно сегодня. Во второй половине Карл Фрэнклин устраивает для Скотта викторину, вспомнит ли он, что он отвечал на вопросы ведущих подкаста 20-лет назад!
- Скотт, почему ты позволяешь писать анонимные комментарии к статьям на своём сайте?
- Я просто не знаю, как установить OAuth.
И множество других замечательных историй о различных конференциях, подкастах и других мероприятиях, а также о том, чему научились в процессе.
.NET Rocks!
.NET Rocks! Episode 1900 with Scott Hanselman!
.NET Rocks! is a weekly talk show for anyone interested in programming on the Microsoft .NET platform. The shows range from introductory information to hardcore geekiness.
👍17
День 1951. #ЧтоНовенького
Вышел Превью Visual Studio 2022 17.11
Microsoft выпустили первый превью Visual Studio 2022 17.11. Вот некоторые новинки.
1. Пул-реквесты
Можно создавать черновики пул-реквестов и создавать описания с помощью шаблонов. Шаблон пул-реквеста по умолчанию будет использоваться при создании нового PR как для GitHub, так и для Azure DevOps. Дополнительную информацию о том, как добавить шаблон пул-реквеста в репозиторий, можно найти в документации GitHub и Azure DevOps.
2. Сочетания клавиш
Добавили
Для функции поиска инструментов (Feature Search) было добавлено сочетание клавиш
3. Отладка и профилирование
До сих пор отладка асинхронного кода, особенно в таких средах, как ASP.NET, была сложной из-за возможности возникновения исключений, переходящих через границы асинхронности. Теперь отладчик Visual Studio автоматически прерывается, когда асинхронный метод возвращает исключение в код платформы. Такой подход облегчает выявление и диагностику проблем в приложениях ASP.NET.
Профилировщик Visual Studio теперь обеспечивает автоматическую декомпиляцию библиотек .NET, когда исходный код недоступен. Декомпиляция кода во время поиска исходного кода, даже без загруженных символов или точного местоположения файлов, позволяет получить представление о структуре кода и проблемах с производительностью. Эта функция особенно полезна для анализа и оптимизации внешнего кода.
4. Файлы vsconfig
Используя файлы *.vsconfig, вы можете убедиться, что у вашей команды есть все необходимые компоненты и расширения, необходимые вашему решению. Многие команды используют файлы *.vsconfig для стандартизации установок Visual Studio. Файлы *.vsconfig можно поместить в репозиторий или каталог решения проекта, а Visual Studio теперь при открытии решения автоматически определит, присутствуют ли в установке все необходимые компоненты. Если нет, предложит их установить.
5. Пакеты NPM в обозревателе решений
Теперь вы сможете посмотреть пакеты NPM в узле Dependencies (Зависимости) в обозревателе решений в проектах JavaScript и TypeScript.
Источники:
- https://www.infoq.com/news/2024/05/vs-2022-preview-1/
- https://learn.microsoft.com/ru-ru/visualstudio/releases/2022/release-notes-preview
Вышел Превью Visual Studio 2022 17.11
Microsoft выпустили первый превью Visual Studio 2022 17.11. Вот некоторые новинки.
1. Пул-реквесты
Можно создавать черновики пул-реквестов и создавать описания с помощью шаблонов. Шаблон пул-реквеста по умолчанию будет использоваться при создании нового PR как для GitHub, так и для Azure DevOps. Дополнительную информацию о том, как добавить шаблон пул-реквеста в репозиторий, можно найти в документации GitHub и Azure DevOps.
2. Сочетания клавиш
Добавили
Ctrl+/
в качестве альтернативного сочетания клавиш для «закомментирования» строк, которое используется по умолчанию во многих других IDE и редакторах кода.Для функции поиска инструментов (Feature Search) было добавлено сочетание клавиш
Ctrl+Shift+P
, которое должно быть знакомо пользователям VS Code для открытия палитры команд.3. Отладка и профилирование
До сих пор отладка асинхронного кода, особенно в таких средах, как ASP.NET, была сложной из-за возможности возникновения исключений, переходящих через границы асинхронности. Теперь отладчик Visual Studio автоматически прерывается, когда асинхронный метод возвращает исключение в код платформы. Такой подход облегчает выявление и диагностику проблем в приложениях ASP.NET.
Профилировщик Visual Studio теперь обеспечивает автоматическую декомпиляцию библиотек .NET, когда исходный код недоступен. Декомпиляция кода во время поиска исходного кода, даже без загруженных символов или точного местоположения файлов, позволяет получить представление о структуре кода и проблемах с производительностью. Эта функция особенно полезна для анализа и оптимизации внешнего кода.
4. Файлы vsconfig
Используя файлы *.vsconfig, вы можете убедиться, что у вашей команды есть все необходимые компоненты и расширения, необходимые вашему решению. Многие команды используют файлы *.vsconfig для стандартизации установок Visual Studio. Файлы *.vsconfig можно поместить в репозиторий или каталог решения проекта, а Visual Studio теперь при открытии решения автоматически определит, присутствуют ли в установке все необходимые компоненты. Если нет, предложит их установить.
5. Пакеты NPM в обозревателе решений
Теперь вы сможете посмотреть пакеты NPM в узле Dependencies (Зависимости) в обозревателе решений в проектах JavaScript и TypeScript.
Источники:
- https://www.infoq.com/news/2024/05/vs-2022-preview-1/
- https://learn.microsoft.com/ru-ru/visualstudio/releases/2022/release-notes-preview
👍19
День 1952. #МоиИнструменты
Операции Перед Коммитом с Husky.NET. Начало
Если вам нужно выполнить операции перед коммитом в Git, вы можете положиться на перехватчики - Git-хуки (Hooks).
Git-хуки — это сценарии, которые запускаются автоматически всякий раз, когда в репозитории Git происходит определённое событие. Они позволяют настраивать внутреннее поведение Git и запускать определённые действия в ключевые моменты жизненного цикла разработки. Расширения Git-хуков позволяют вам подключать к обычному потоку Git специальные функции, такие как проверка сообщений Git, форматирование кода и т.д.
Категории Git-хуков:
1. Клиентские на коммит – выполняются при
2. Клиентские на email - выполняются при
3. Клиентские на другие операции - запускаются в локальном репозитории при операциях вроде
4. Серверные - запускаются после получения коммита в удалённом репозитории и могут отклонить операцию
Мы сосредоточимся на клиентских хуках на коммит. Они бывают 4х видов:
1. pre-commit - вызывается первым при
2. prepare-commit-msg – может использоваться для редактирования сообщения коммита по умолчанию, когда оно генерируется автоматическим инструментом.
3. commit-msg - может использоваться для проверки или изменения сообщения коммита после его ввода пользователем.
4. post-commit - вызывается после корректного выполнения коммита и обычно используется для запуска уведомлений.
Используем Husky.NET
Для Husky.NET необходимо добавить файл tool-manifest в корень решения:
Эта команда добавит файл .config/dotnet-tools.json со списком всех внешних инструментов, используемых dotnet. Теперь установим Husky:
И добавим его в приложение .NET:
Это создаст в корне решения папку .husky, содержащую файлы, которые будут использоваться для Git-хуков. Создадим хук:
Эта команда создаст файл pre-commit (без расширения) в папке .husky. На данный момент он ничего не делает, поэтому изменим его. Следующий текст хука будет компилировать код, форматировать текст (используя правила из файла .editorconfig) и выполнять тесты:
Всё готово! Хотя, погодите-ка…
Окончание следует…
Источник: https://www.code4it.dev/blog/husky-dotnet-precommit-hooks/
Операции Перед Коммитом с Husky.NET. Начало
Если вам нужно выполнить операции перед коммитом в Git, вы можете положиться на перехватчики - Git-хуки (Hooks).
Git-хуки — это сценарии, которые запускаются автоматически всякий раз, когда в репозитории Git происходит определённое событие. Они позволяют настраивать внутреннее поведение Git и запускать определённые действия в ключевые моменты жизненного цикла разработки. Расширения Git-хуков позволяют вам подключать к обычному потоку Git специальные функции, такие как проверка сообщений Git, форматирование кода и т.д.
Категории Git-хуков:
1. Клиентские на коммит – выполняются при
git commit
в локальном репозитории;2. Клиентские на email - выполняются при
git am
— команды, позволяющей интегрировать почту и репозитории Git (если интересует, вот документация);3. Клиентские на другие операции - запускаются в локальном репозитории при операциях вроде
git rebase
;4. Серверные - запускаются после получения коммита в удалённом репозитории и могут отклонить операцию
git push
.Мы сосредоточимся на клиентских хуках на коммит. Они бывают 4х видов:
1. pre-commit - вызывается первым при
git commit
(если вы не используете флаг -m
, то перед запросом о добавлении сообщения) и может использоваться для проверки моментального снимка фиксируемого кода.2. prepare-commit-msg – может использоваться для редактирования сообщения коммита по умолчанию, когда оно генерируется автоматическим инструментом.
3. commit-msg - может использоваться для проверки или изменения сообщения коммита после его ввода пользователем.
4. post-commit - вызывается после корректного выполнения коммита и обычно используется для запуска уведомлений.
Используем Husky.NET
Для Husky.NET необходимо добавить файл tool-manifest в корень решения:
dotnet new tool-manifest
Эта команда добавит файл .config/dotnet-tools.json со списком всех внешних инструментов, используемых dotnet. Теперь установим Husky:
dotnet tool install Husky
И добавим его в приложение .NET:
dotnet husky install
Это создаст в корне решения папку .husky, содержащую файлы, которые будут использоваться для Git-хуков. Создадим хук:
dotnet husky add pre-commit
Эта команда создаст файл pre-commit (без расширения) в папке .husky. На данный момент он ничего не делает, поэтому изменим его. Следующий текст хука будет компилировать код, форматировать текст (используя правила из файла .editorconfig) и выполнять тесты:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
echo 'Building code'
dotnet build
echo 'Formatting code'
dotnet format
echo 'Running tests'
dotnet test
Всё готово! Хотя, погодите-ка…
Окончание следует…
Источник: https://www.code4it.dev/blog/husky-dotnet-precommit-hooks/
👍11
День 1953. #МоиИнструменты
Операции Перед Коммитом с Husky.NET. Продолжение
Начало
Управляем командой dotnet format с помощью Husky.NET
В приведённом выше примере есть проблема. Т.к. dotnet format изменяет исходные файлы, и учитывая, что моментальный снимок кода уже был создан до выполнения хука, все изменённые файлы не будут частью окончательного коммита! Также
1. Выполнить git add
Выполнение
-
-
2. Пробный прогон dotnet format
Флаг
Таким образом, если есть что форматировать, весь коммит будет отменён. Затем вам придётся запустить
Кроме того, вы не рискуете включить в снимок файлы, которые хотите сохранить в промежуточном состоянии, чтобы добавить их в последующий коммит.
3. dotnet format только для файлов коммита с помощью Husky.NET Task Runner
В папке .husky есть файл task-runner.json. Он позволяет создавать собственные сценарии с именем, группой, выполняемой командой и соответствующими параметрами. Изменим его так, чтобы
Здесь мы указали имя задачи (
или группу задач:
Теперь заменим команду
Да, сборку можно не делать отдельно, т.к. она запускается перед тестами.
И последнее. Если вы захотите сделать коммит без выполнения хука, используйте флаг
Источник: https://www.code4it.dev/blog/husky-dotnet-precommit-hooks/
Операции Перед Коммитом с Husky.NET. Продолжение
Начало
Управляем командой dotnet format с помощью Husky.NET
В приведённом выше примере есть проблема. Т.к. dotnet format изменяет исходные файлы, и учитывая, что моментальный снимок кода уже был создан до выполнения хука, все изменённые файлы не будут частью окончательного коммита! Также
dotnet format
выполняет проверку каждого файла в решении, а не только тех, которые являются частью текущего снимка. Так операция может занять много времени. Есть 3 подхода к решению этой проблемы.1. Выполнить git add
Выполнение
git add .
после dotnet format
сделает все изменения частью коммита, но:-
dotnet format
всё ещё будет затрагивать все файлы;-
git add .
добавит все изменённые файлы в коммит, а не только те, которые вы хотели добавить (возможно потому что другие изменения должны были быть включены в другой коммит).2. Пробный прогон dotnet format
Флаг
--verify-no-changes
команды dotnet format
приведёт к возвращению ошибки, если хотя бы один файл необходимо обновить из-за правил форматирования.Таким образом, если есть что форматировать, весь коммит будет отменён. Затем вам придётся запустить
dotnet format
для всего решения, исправить ошибки, добавить изменения в git и попробовать сделать коммит ещё раз. Это более длительный процесс, но он позволяет вам иметь полный контроль над отформатированными файлами.Кроме того, вы не рискуете включить в снимок файлы, которые хотите сохранить в промежуточном состоянии, чтобы добавить их в последующий коммит.
3. dotnet format только для файлов коммита с помощью Husky.NET Task Runner
В папке .husky есть файл task-runner.json. Он позволяет создавать собственные сценарии с именем, группой, выполняемой командой и соответствующими параметрами. Изменим его так, чтобы
dotnet format
затрагивал только файлы, предназначенные для коммита:{
"tasks": [
{
"name": "dotnet-format-staged-files",
"group": "pre-commit-operations",
"command": "dotnet",
"args": ["format", "--include", "${staged}"],
"include": ["**/*.cs"]
}
]
}
Здесь мы указали имя задачи (
dotnet-format-staged-files
), команду для запуска (dotnet
с параметрами args
) и фильтр списка файлов, подлежащих форматированию, используя параметр ${staged}
, который заполняется Husky.NET. Мы также добавили задачу в группу pre-commit-operations
, которую мы можем использовать для задач, выполняющихся вместе. Так можно запустить отдельную задачу:dotnet husky run --name dotnet-format-staged-files
или группу задач:
dotnet husky run --group pre-commit-operations
Теперь заменим команду
dotnet format
в файле pre-commit на одну из приведённых выше, а также добавим флаги --no-restore
для сборки и теста, чтобы ускорить их выполнение:#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
echo 'Format'
dotnet husky run --name dotnet-format-staged-files
echo 'Build'
dotnet build --no-restore
echo 'Test'
dotnet test --no-restore
echo 'Completed pre-commit changes'
Да, сборку можно не делать отдельно, т.к. она запускается перед тестами.
И последнее. Если вы захотите сделать коммит без выполнения хука, используйте флаг
--no-verify
:git commit -m "my message" --no-verify
Источник: https://www.code4it.dev/blog/husky-dotnet-precommit-hooks/
👍6
День 1954. #ЗаметкиНаПолях
Создаём Мульти-Архитектурный Образ Docker для Приложения .NET
Мы переживаем переходный период, когда архитектуры x64 — не единственные доступные. Apple перешла на ARM с чипом M1, и Microsoft сейчас также продвигает ARM. Если вы хотите запускать своё приложение на архитектурах ARM64 и x64, вам необходимо создать образ Docker для каждой архитектуры. Docker поддерживает образы с несколькими архитектурами, что позволяет создавать один образ, который может работать на нескольких архитектурах.
Чтобы создать образ Docker, поддерживающий несколько архитектур, необходимо создать несколько образов для каждой архитектуры, а затем создать манифест, который будет ссылаться на все образы. Манифест будет использоваться клиентом Docker для получения правильного образа для текущей архитектуры. Вот список тегов, которые нужно создать:
- mysampleapp:1.0.0-x64 – образ для x64
- mysampleapp:1.0.0-arm64 – образ для ARM64
- mysampleapp:1.0.0 – манифест, который ссылается на образы выше.
Для создания образов можно использовать команду
Создадим новый проект:
Создадим 2 образа для x64 и ARM64:
Теперь можно объединить образы в одном манифесте и добавить манифест в реестр:
Источник: https://www.meziantou.net/create-a-multi-arch-docker-image-for-a-dotnet-application.htm
Создаём Мульти-Архитектурный Образ Docker для Приложения .NET
Мы переживаем переходный период, когда архитектуры x64 — не единственные доступные. Apple перешла на ARM с чипом M1, и Microsoft сейчас также продвигает ARM. Если вы хотите запускать своё приложение на архитектурах ARM64 и x64, вам необходимо создать образ Docker для каждой архитектуры. Docker поддерживает образы с несколькими архитектурами, что позволяет создавать один образ, который может работать на нескольких архитектурах.
Чтобы создать образ Docker, поддерживающий несколько архитектур, необходимо создать несколько образов для каждой архитектуры, а затем создать манифест, который будет ссылаться на все образы. Манифест будет использоваться клиентом Docker для получения правильного образа для текущей архитектуры. Вот список тегов, которые нужно создать:
- mysampleapp:1.0.0-x64 – образ для x64
- mysampleapp:1.0.0-arm64 – образ для ARM64
- mysampleapp:1.0.0 – манифест, который ссылается на образы выше.
Для создания образов можно использовать команду
dotnet publish
с несколькими свойствами для настройки образа. Это проще, чем создавать Dockerfile и быстрее, чем собирать образ.Создадим новый проект:
dotnet new web
Создадим 2 образа для x64 и ARM64:
powershell
$registry = "ghcr.io"
$image = "myapps/mysampleapp"
$tag = "latest"
dotnet publish -p:PublishProfile=DefaultContainer --configuration Release --os linux --arch x64 -p:ContainerImageTag=$tag-x64 -p:ContainerRepository=$image -p:ContainerRegistry=$registry
dotnet publish -p:PublishProfile=DefaultContainer --configuration Release --os linux --arch arm64 -p:ContainerImageTag=$tag-arm64 -p:ContainerRepository=$image -p:ContainerRegistry=$registry
Теперь можно объединить образы в одном манифесте и добавить манифест в реестр:
docker manifest create "$registry/${image}:$tag" "$registry/${image}:$tag-x64" "$registry/${image}:$tag-arm64"
docker manifest push "$registry/${image}:$tag"
Источник: https://www.meziantou.net/create-a-multi-arch-docker-image-for-a-dotnet-application.htm
👍12
День 1955. #Карьера
Ведите Дневник Разработчика. Начало
Разработчики погрязли в абстракциях! От проектирования системы до мельчайших деталей реализации — мы храним в голове огромное количество информации. На уровне проекта менеджер проекта, владелец продукта, тех. менеджер, бизнес аналитик (иногда все в одном лице) помогают нам понять, что делать дальше. Инструменты управления проектами, вроде Jira, отслеживают наш прогресс. Но на уровне кода легко заблудиться.
Дневник разработчика — это инструмент для отслеживания того, что вы делаете и почему. Поначалу это может показаться рутинной работой, но ведение дневника сэкономит массу времени и избавит от многих головных болей во время работы.
Зачем?
Вы напишете лучший код, если сможете сосредоточить 100% своего внимания на решении одной чётко определенной проблемы за раз, и будете расти как разработчик, анализируя, что работает для вас, а что нет. Дневник — место, где можно определить проблему, которую вы решаете, и записать, что вы пробовали и что сработало.
1. Определяем, что делать
Функция продукта может быть чётко определена, а реализация – нет. Используйте дневник, чтобы обозначить всё, что нужно для выполнения задачи, и набросать план действий.
2. Уменьшаем двусмысленность
Не пытайтесь преодолеть путаницу, написав кучу кода, это может занять часы. Потратьте пять минут на то, чтобы изложить на бумаге свои сомнения и гипотезу. Чего вы не знаете? Как это узнать? Как вы думаете, что произойдет?
3. Учимся на своём опыте
Выполнив работу, вы можете точно прочитать, что вы сделали и как вы к этому подошли, и извлечь уроки из того, что было сложно, а что удалось сделать хорошо.
4. Не отвлекаемся
Отвлекаться – естественно. Вы можете наткнуться на некачественный код и захотеть его отрефакторить, обнаружить, что работаете с той частью кодовой базы, которую не хотели трогать, а теперь нужно что-то изучить, и т.п. Постоянное переключение контекста затрудняет выполнение глубокой работы. Запишите мысли и вопросы, которые у вас возникают, в дневник, и вернётесь к ним позже.
5. Выбрасываем заботы из головы
Можно использовать дневник, чтобы отслеживать свои эмоции. «Утренние страницы» — популярный метод очистки беспорядка в голове в начале каждого дня, можно попробовать это. Нервничаете, тревожитесь, взволнованы? Запишите чувства на бумаге, чтобы очистить голову и уделить всё внимание техническим проблемам.
Продолжение следует…
Источник: https://stackoverflow.blog/2024/05/22/you-should-keep-a-developer-s-journal/
Ведите Дневник Разработчика. Начало
Разработчики погрязли в абстракциях! От проектирования системы до мельчайших деталей реализации — мы храним в голове огромное количество информации. На уровне проекта менеджер проекта, владелец продукта, тех. менеджер, бизнес аналитик (иногда все в одном лице) помогают нам понять, что делать дальше. Инструменты управления проектами, вроде Jira, отслеживают наш прогресс. Но на уровне кода легко заблудиться.
Дневник разработчика — это инструмент для отслеживания того, что вы делаете и почему. Поначалу это может показаться рутинной работой, но ведение дневника сэкономит массу времени и избавит от многих головных болей во время работы.
Зачем?
Вы напишете лучший код, если сможете сосредоточить 100% своего внимания на решении одной чётко определенной проблемы за раз, и будете расти как разработчик, анализируя, что работает для вас, а что нет. Дневник — место, где можно определить проблему, которую вы решаете, и записать, что вы пробовали и что сработало.
1. Определяем, что делать
Функция продукта может быть чётко определена, а реализация – нет. Используйте дневник, чтобы обозначить всё, что нужно для выполнения задачи, и набросать план действий.
2. Уменьшаем двусмысленность
Не пытайтесь преодолеть путаницу, написав кучу кода, это может занять часы. Потратьте пять минут на то, чтобы изложить на бумаге свои сомнения и гипотезу. Чего вы не знаете? Как это узнать? Как вы думаете, что произойдет?
3. Учимся на своём опыте
Выполнив работу, вы можете точно прочитать, что вы сделали и как вы к этому подошли, и извлечь уроки из того, что было сложно, а что удалось сделать хорошо.
4. Не отвлекаемся
Отвлекаться – естественно. Вы можете наткнуться на некачественный код и захотеть его отрефакторить, обнаружить, что работаете с той частью кодовой базы, которую не хотели трогать, а теперь нужно что-то изучить, и т.п. Постоянное переключение контекста затрудняет выполнение глубокой работы. Запишите мысли и вопросы, которые у вас возникают, в дневник, и вернётесь к ним позже.
5. Выбрасываем заботы из головы
Можно использовать дневник, чтобы отслеживать свои эмоции. «Утренние страницы» — популярный метод очистки беспорядка в голове в начале каждого дня, можно попробовать это. Нервничаете, тревожитесь, взволнованы? Запишите чувства на бумаге, чтобы очистить голову и уделить всё внимание техническим проблемам.
Продолжение следует…
Источник: https://stackoverflow.blog/2024/05/22/you-should-keep-a-developer-s-journal/
👍16
День 1956. #Карьера
Ведите Дневник Разработчика. Продолжение
Начало. Зачем?
Как?
1. Настройка
Выберите место. Подойдёт любой текстовый редактор, даже редактор кода и файл markdown (только добавьте его в .gitignore). Чем проще этот этап, тем лучше. Лучше использовать рабочую машину, т.к. возможно понадобится вставлять фрагменты кода.
Дневник — ваш личный документ, в котором можно систематизировать и обработать мысли. Текст должен быть понятным и читабельным для вас. Стремитесь к формату списка дел, а не к сочинению. Не зацикливайтесь на форматировании, организации, формулировках, опечатках. Если вы можете ориентироваться в тексте – всё хорошо!
Для начала попробуйте разбивать текст по дням. Каждый день записывайте свою цель (можно разбить её на задачи) и краткое резюме. Кроме того, у вас могут быть разделы для заметок, полезные ссылки, просто мысли о будущем и т.п. Главное – дневник можно настраивать под себя.
2. Прежде чем писать код
В начале каждого рабочего сеанса (спринта, рабочего дня, сессии «помидора») определите цель сеанса, даже если она кажется очевидной. Чего достичь сегодня? Есть ли ясная и чётко определённая задача по написанию кода, которую необходимо выполнить? Нужно ли что-то изучить в кодовой базе? Нужно проверить гипотезу? Как уменьшить двусмысленность?
Иногда будет просто, иногда сложно определиться с целями, иногда будет жгучее желание побыстрей начать писать код. Если вы чувствуете дискомфорт при формулировании своих мыслей, возможно, вы недостаточно ясно представляете своё решение. Отлично! Именно поэтому вы и ведёте дневник.
3. Пока пишете код
- Застрял – запиши
Если обнаружите, что обдумываете проблему дольше минуты, запишите свои мысли в дневник. Если вы застряли в поиске бага, запишите всё, что пробовали до сих пор. Так будет легче организовать свои мысли и обратиться за помощью, если она вам понадобится.
- Разобрался - запиши
Запишите решение или логику, которая помогла решить проблему, или в чём была ошибка. Не судите себя, просто опишите как дела. Это будет полезно для определения того, что работает для вас в долгосрочной перспективе.
- Выбросьте идеи, вопросы и задачи из головы
Работая над кодом, вы естественным образом будете генерировать идеи и вопросы. В большинстве случаев не стоит прерывать работу ради них. Записывание этих задач поможет разгрузить мозг и сосредоточиться на коде. Если задача чётко определена, вы можете даже написать TODO прямо в коде. Но большинство идей не настолько детализированы, поэтому лучше записать их в дневник. Для них даже могут быть отдельные разделы «Вопросы» или «Идеи».
4. Когда закончили задачу
В конце сеанса кодирования запишите, как всё прошло. Помните, это только для вас. Будьте откровенны. Смогли ли выполнить поставленную задачу? Было ли что-то сложнее, чем вы ожидали? Вы неправильно оценили сложность задачи? Можете ли вы определить, что вас расстраивало? Хотели бы вы сделать что-нибудь по-другому, когда вернётесь к этому завтра? Где-то застряли? Сделали ли что-нибудь, чем гордитесь? Короче говоря, сделайте свою собственную ретроспективу своего дня.
Окончание следует…
Источник: https://stackoverflow.blog/2024/05/22/you-should-keep-a-developer-s-journal/
Ведите Дневник Разработчика. Продолжение
Начало. Зачем?
Как?
1. Настройка
Выберите место. Подойдёт любой текстовый редактор, даже редактор кода и файл markdown (только добавьте его в .gitignore). Чем проще этот этап, тем лучше. Лучше использовать рабочую машину, т.к. возможно понадобится вставлять фрагменты кода.
Дневник — ваш личный документ, в котором можно систематизировать и обработать мысли. Текст должен быть понятным и читабельным для вас. Стремитесь к формату списка дел, а не к сочинению. Не зацикливайтесь на форматировании, организации, формулировках, опечатках. Если вы можете ориентироваться в тексте – всё хорошо!
Для начала попробуйте разбивать текст по дням. Каждый день записывайте свою цель (можно разбить её на задачи) и краткое резюме. Кроме того, у вас могут быть разделы для заметок, полезные ссылки, просто мысли о будущем и т.п. Главное – дневник можно настраивать под себя.
2. Прежде чем писать код
В начале каждого рабочего сеанса (спринта, рабочего дня, сессии «помидора») определите цель сеанса, даже если она кажется очевидной. Чего достичь сегодня? Есть ли ясная и чётко определённая задача по написанию кода, которую необходимо выполнить? Нужно ли что-то изучить в кодовой базе? Нужно проверить гипотезу? Как уменьшить двусмысленность?
Иногда будет просто, иногда сложно определиться с целями, иногда будет жгучее желание побыстрей начать писать код. Если вы чувствуете дискомфорт при формулировании своих мыслей, возможно, вы недостаточно ясно представляете своё решение. Отлично! Именно поэтому вы и ведёте дневник.
3. Пока пишете код
- Застрял – запиши
Если обнаружите, что обдумываете проблему дольше минуты, запишите свои мысли в дневник. Если вы застряли в поиске бага, запишите всё, что пробовали до сих пор. Так будет легче организовать свои мысли и обратиться за помощью, если она вам понадобится.
- Разобрался - запиши
Запишите решение или логику, которая помогла решить проблему, или в чём была ошибка. Не судите себя, просто опишите как дела. Это будет полезно для определения того, что работает для вас в долгосрочной перспективе.
- Выбросьте идеи, вопросы и задачи из головы
Работая над кодом, вы естественным образом будете генерировать идеи и вопросы. В большинстве случаев не стоит прерывать работу ради них. Записывание этих задач поможет разгрузить мозг и сосредоточиться на коде. Если задача чётко определена, вы можете даже написать TODO прямо в коде. Но большинство идей не настолько детализированы, поэтому лучше записать их в дневник. Для них даже могут быть отдельные разделы «Вопросы» или «Идеи».
4. Когда закончили задачу
В конце сеанса кодирования запишите, как всё прошло. Помните, это только для вас. Будьте откровенны. Смогли ли выполнить поставленную задачу? Было ли что-то сложнее, чем вы ожидали? Вы неправильно оценили сложность задачи? Можете ли вы определить, что вас расстраивало? Хотели бы вы сделать что-нибудь по-другому, когда вернётесь к этому завтра? Где-то застряли? Сделали ли что-нибудь, чем гордитесь? Короче говоря, сделайте свою собственную ретроспективу своего дня.
Окончание следует…
Источник: https://stackoverflow.blog/2024/05/22/you-should-keep-a-developer-s-journal/
👍18
День 1957. #Карьера
Ведите Дневник Разработчика. Окончание
Начало. Зачем?
Продолжение. Как?
Ключи к успеху
1. Создаём привычку
Возьмите за привычку писать в начале и в конце каждого сеанса кодирования. Держите дневник поблизости - всегда на расстоянии одной вкладки. У вас должна быть возможность проверить свои заметки или сразу сделать дополнительные заметки. Ваш дневник становится всё более ценным, чем дольше вы его ведёте, поскольку начинают проявляться закономерности.
2. Пишем прямо
Выразите то, что думаете, словами, которые приходят на ум, как можно короче. Никто не ставит оценок, не нужно никого впечатлять красноречием.
3. Думаем о потребностях
Дневник должен включать в себя всё, что вам нужно для эффективной работы. Например, полезно озвучивать для себя свои тревоги и негативные мысли: «Не могу поверить, что уже третий день занимаюсь этой проблемой» или «Чувствую себя самозванцем». Это неприятные мысли, но, если они у вас всё равно возникают, запишите их на бумаге, чтобы сосредоточиться на работе, а не зацикливаться на размышлениях.
4. Учимся на своём опыте
В конце спринта, месяца или квартала выделите немного времени для просмотра своего дневника. Не нужно читать мелкие детали, обратите внимание на то, что вызывало трудности и что помогало их решать, и чего вы достигали каждый день.
Это полезно для:
- Понимания, какой объём работы вы способны выполнить;
- Встреч 1 на 1 с начальником;
- Помощи коллегам, чтобы помочь повысить уровень вашей команды;
- Документирования ваших достижений для будущих разговоров о карьерном росте.
Запишите выводы, полученные в результате размышлений, в том же журнале, например, в разделе «Выводы из этого спринта/проекта/квартала». Опять же, это заставит вас задуматься о том, что вы делаете. Подумайте о том, чтобы поделиться своими знаниями с командой и руководителем. Если у вас возникли проблемы с концепцией/инструментом/частью кодовой базы, скорее всего, у ваших коллег (особенно новичков) тоже.
5. Бережём внимание
Написание текста параллельно с обычной работой по программированию может показаться совершенно другой работой, но, если вы будете придерживаться этого, это станет вашей второй натурой и сэкономит вам массу времени. Гораздо лучше запутаться, описывая мысли в начале проекта, чем когда вы в середине проекта написали кучу кода в десятках файлах. Потратьте пять минут, чтобы спланировать свой день сейчас вместо того, чтобы бегать по кругу позже.
Хороший дневник разработчика должен делать три вещи:
1) Подтолкнуть к обдумыванию своих идей и планированию каждого дня, прежде чем начинать программировать.
2) Заставить более внимательно относиться к своим успехам и трудностям, чтобы вы могли повысить свой уровень.
3) Очищать ваш разум от всего, что мешает кодированию.
Попробуйте вести журнал разработки для вашего следующего проекта или спринта. Вы можете быть удивлены тем, насколько вы станете продуктивнее!
Источник: https://stackoverflow.blog/2024/05/22/you-should-keep-a-developer-s-journal/
Ведите Дневник Разработчика. Окончание
Начало. Зачем?
Продолжение. Как?
Ключи к успеху
1. Создаём привычку
Возьмите за привычку писать в начале и в конце каждого сеанса кодирования. Держите дневник поблизости - всегда на расстоянии одной вкладки. У вас должна быть возможность проверить свои заметки или сразу сделать дополнительные заметки. Ваш дневник становится всё более ценным, чем дольше вы его ведёте, поскольку начинают проявляться закономерности.
2. Пишем прямо
Выразите то, что думаете, словами, которые приходят на ум, как можно короче. Никто не ставит оценок, не нужно никого впечатлять красноречием.
3. Думаем о потребностях
Дневник должен включать в себя всё, что вам нужно для эффективной работы. Например, полезно озвучивать для себя свои тревоги и негативные мысли: «Не могу поверить, что уже третий день занимаюсь этой проблемой» или «Чувствую себя самозванцем». Это неприятные мысли, но, если они у вас всё равно возникают, запишите их на бумаге, чтобы сосредоточиться на работе, а не зацикливаться на размышлениях.
4. Учимся на своём опыте
В конце спринта, месяца или квартала выделите немного времени для просмотра своего дневника. Не нужно читать мелкие детали, обратите внимание на то, что вызывало трудности и что помогало их решать, и чего вы достигали каждый день.
Это полезно для:
- Понимания, какой объём работы вы способны выполнить;
- Встреч 1 на 1 с начальником;
- Помощи коллегам, чтобы помочь повысить уровень вашей команды;
- Документирования ваших достижений для будущих разговоров о карьерном росте.
Запишите выводы, полученные в результате размышлений, в том же журнале, например, в разделе «Выводы из этого спринта/проекта/квартала». Опять же, это заставит вас задуматься о том, что вы делаете. Подумайте о том, чтобы поделиться своими знаниями с командой и руководителем. Если у вас возникли проблемы с концепцией/инструментом/частью кодовой базы, скорее всего, у ваших коллег (особенно новичков) тоже.
5. Бережём внимание
Написание текста параллельно с обычной работой по программированию может показаться совершенно другой работой, но, если вы будете придерживаться этого, это станет вашей второй натурой и сэкономит вам массу времени. Гораздо лучше запутаться, описывая мысли в начале проекта, чем когда вы в середине проекта написали кучу кода в десятках файлах. Потратьте пять минут, чтобы спланировать свой день сейчас вместо того, чтобы бегать по кругу позже.
Хороший дневник разработчика должен делать три вещи:
1) Подтолкнуть к обдумыванию своих идей и планированию каждого дня, прежде чем начинать программировать.
2) Заставить более внимательно относиться к своим успехам и трудностям, чтобы вы могли повысить свой уровень.
3) Очищать ваш разум от всего, что мешает кодированию.
Попробуйте вести журнал разработки для вашего следующего проекта или спринта. Вы можете быть удивлены тем, насколько вы станете продуктивнее!
Источник: https://stackoverflow.blog/2024/05/22/you-should-keep-a-developer-s-journal/
👍9
День 1958. #ЧтоНовенького #CSharp13
Типы-Расширения
Начиная с C# 3, методы расширения позволяют добавлять методы к базовому типу, даже если вы не можете изменить его код. LINQ — пример набора методов расширения IEnumerable<T>. Методы расширения LINQ выглядят так, как если бы они были методами экземпляра базового типа.
C# 13 идёт дальше, добавляя типы-расширения. Это новая разновидность типов языка, которая предоставляет элементы расширения для базового типа. Расширение включает методы, свойства и другие члены, которые могут быть как экземплярными, так и статическими. Типы-расширения экземпляра не могут хранить состояние, например, не могут включать экземплярные поля, но могут получать доступ к состоянию базового типа.
Виды
1. Неявные
Применяются ко всем экземплярам базового типа так же, как методы расширения.
2. Явные
Применяются только к экземплярам базового типа, которые были преобразованы в тип явного расширения (по аналогии с явной реализацией интерфейсов).
Пусть у нас есть базовые типы и нет доступа к изменению их кода:
Небольшой код LINQ поможет определить, является ли человек лидом. Но мы не хотим писать его каждый раз, поэтому можно написать метод расширения и контролировать доступ к нему через пространства имён. Или можно использовать неявный тип-расширение и предоставить свойство IsLead всем экземплярам Person:
Явные расширения позволяют предоставлять дополнительные возможности конкретным экземплярам типа. Например, чтобы узнать, какие команды возглавляет человек, явное расширение может предоставлять свойство Teams только лидам (через приведение экземпляра Person к типу Lead):
Как неявные, так и явные типы-расширения поддерживают и статические, и экземплярные члены. Вариант использования статических членов — предоставить значения по умолчанию, специфичные для вашего сценария. В данном случае у нас одна компания, и указывать её каждый раз при создании человека неудобно:
С точки зрения использования типы-расширения позволяют упростить код, обеспечивающий важную работу и логику приложения, настраивая конкретные экземпляры базовых объектов под ваши нужды. С технической точки зрения типы-расширения представляют собой усовершенствование методов расширения, которые вы используете сегодня.
Источник: https://devblogs.microsoft.com/dotnet/dotnet-build-2024-announcements/
Типы-Расширения
Начиная с C# 3, методы расширения позволяют добавлять методы к базовому типу, даже если вы не можете изменить его код. LINQ — пример набора методов расширения IEnumerable<T>. Методы расширения LINQ выглядят так, как если бы они были методами экземпляра базового типа.
C# 13 идёт дальше, добавляя типы-расширения. Это новая разновидность типов языка, которая предоставляет элементы расширения для базового типа. Расширение включает методы, свойства и другие члены, которые могут быть как экземплярными, так и статическими. Типы-расширения экземпляра не могут хранить состояние, например, не могут включать экземплярные поля, но могут получать доступ к состоянию базового типа.
Виды
1. Неявные
Применяются ко всем экземплярам базового типа так же, как методы расширения.
2. Явные
Применяются только к экземплярам базового типа, которые были преобразованы в тип явного расширения (по аналогии с явной реализацией интерфейсов).
Пусть у нас есть базовые типы и нет доступа к изменению их кода:
public class Person()
{
public string FirstName { get; init; }
public string LastName { get; init; }
public Company Company { get; init; }
}
public class Company()
{
public string Name { get; init; }
public List<Team> Teams { get; init; }
}
public class Team()
{
public string TeamName { get; init; }
public Person Lead { get; init; }
public IEnumerable<Person> Members { get; init; }
}
Небольшой код LINQ поможет определить, является ли человек лидом. Но мы не хотим писать его каждый раз, поэтому можно написать метод расширения и контролировать доступ к нему через пространства имён. Или можно использовать неявный тип-расширение и предоставить свойство IsLead всем экземплярам Person:
public implicit extension PersonExtension for Person
{
public bool IsLead
=> this.Company
.Teams
.Any(team => team.Lead == this);
}
// Использование
if (person.IsLead) { … }
Явные расширения позволяют предоставлять дополнительные возможности конкретным экземплярам типа. Например, чтобы узнать, какие команды возглавляет человек, явное расширение может предоставлять свойство Teams только лидам (через приведение экземпляра Person к типу Lead):
public explicit extension Lead for Person
{
public IEnumerable<Team> Teams
=> this.Company
.Teams
.Where(team => team.Lead == this);
}
Как неявные, так и явные типы-расширения поддерживают и статические, и экземплярные члены. Вариант использования статических членов — предоставить значения по умолчанию, специфичные для вашего сценария. В данном случае у нас одна компания, и указывать её каждый раз при создании человека неудобно:
public implicit extension CompanyExtension for Company
{
private static Company company
= new Company("C# Design");
public static Person CreatePerson(
string firstName, string lastName)
=> new(firstName, lastName, company);
}
// Использование
var person = Company
.CreatePerson("Jon", "Smith");
// … добавляем ещё людей и команды
if (person.IsLead)
{
Lead lead = person;
PrintReport(lead.Teams);
}
С точки зрения использования типы-расширения позволяют упростить код, обеспечивающий важную работу и логику приложения, настраивая конкретные экземпляры базовых объектов под ваши нужды. С технической точки зрения типы-расширения представляют собой усовершенствование методов расширения, которые вы используете сегодня.
Источник: https://devblogs.microsoft.com/dotnet/dotnet-build-2024-announcements/
👍24
День 1959. #ЗаметкиНаПолях
Что Такое Идемпотентность в Программных Системах? Начало
Вы часто встретите термин «идемпотентный» в ПО, особенно при разработке распределённых облачных систем. На первый взгляд эта концепция кажется простой для понимания, но важно знать тонкости идемпотентности, если вы хотите, чтобы ваши системы были масштабируемыми и надёжными.
Что это?
Возьмём для примера пульт ДУ от телевизора, который наверняка валяется у вас в гостиной. На нём обычно есть кнопки вкл./выкл., кнопки перемещения по каналам вперёд/назад и кнопки с цифрами, переключающие на конкретный канал. Так вот, независимо от того, сколько раз вы будете нажимать кнопку с цифрой канала, например, 5, вы всегда будете попадать на 5й канал (отбросим для простоты возможность включения двузначных каналов). Поэтому эта операция идемпотентна. Однако, нажатие кнопки вкл./выкл. или кнопок перемещения по каналам вверх/вниз каждый раз будет приводить к разному результату, в зависимости от текущего состояния системы, и многократное нажатие приведёт в систему в другое (неизвестное) состояние. Поэтому эта операция не идемпотентна.
Почему это важно?
Концепция идемпотентности важна в распределённых системах, поскольку трудно получить действительно надежные гарантии того, сколько раз команда будет вызываться или обрабатываться.
Сети по своей сути ненадёжны, поэтому большинство распределённых систем не могут гарантировать однократную доставку или обработку сообщений, даже при использовании брокера сообщений, вроде RabbitMQ, Azure Service Bus или Amazon SQS. Большинство брокеров предлагают доставку «хотя бы раз», полагаясь на то, что логика повторяет обработку столько раз, сколько необходимо, пока не будет подтверждено, что обработка сообщения завершена.
Это означает, что, если сообщение не может быть обработано по какой-либо причине, оно будет отправлено повторно. Допустим, у нас есть обработчик сообщений, как ТВ, описанный выше. Если сообщение однозначно, как кнопка 5, то легко написать код обработки, независимо от того, сколько раз получено сообщение. Но если это сообщение «следующий канал», ситуация усложняется. Поэтому, если каждый обработчик сообщений в нашей системе идемпотентен, мы можем повторять любое сообщение столько раз, сколько захотим, и это не повлияет на общую корректность системы.
Почему бы не сделать все обработчики идемпотентными?
Это сложно. Допустим, нужно создать нового пользователя в БД и опубликовать событие UserCreated, чтобы другие части системы знали, что произошло. Псевдокод будет примерно таким:
Теоретически - ОК, но что, если брокер сообщений не поддерживает транзакции? (Спойлер: большинство не поддерживают!) Если между этими двумя строками кода произойдет сбой, запись в базе данных будет создана, но сообщение UserCreated не будет опубликовано. При повторной отправке сообщения будет записана новая запись в БД, а затем сообщение будет опубликовано.
Эти дополнительные записи-зомби создаются в БД, большую часть времени дублируя действительные записи, без какого-либо сообщения в остальную часть системы. Это может быть трудно даже заметить, и ещё труднее потом навести порядок.
А если изменить порядок, и сначала отправлять сообщение, а потом сохранять пользователя? Теперь у нас обратная проблема. Мы создаём призрачное сообщение — объявление остальной части системы о событии, которое на самом деле не произошло. Если кто-нибудь попытается найти этого пользователя, то не найдёт, поскольку он не был создан. Но другие процессы продолжат работать на основе этого сообщения, возможно, выставляя счета, но не доставляя заказов!
При проектировании надёжной системы нужно думать, что произойдёт, если на какой-либо строке кода кто-то выдернет кабель питания сервера.
Окончание следует…
Источник: https://particular.net/blog/what-does-idempotent-mean
Что Такое Идемпотентность в Программных Системах? Начало
Вы часто встретите термин «идемпотентный» в ПО, особенно при разработке распределённых облачных систем. На первый взгляд эта концепция кажется простой для понимания, но важно знать тонкости идемпотентности, если вы хотите, чтобы ваши системы были масштабируемыми и надёжными.
Что это?
Возьмём для примера пульт ДУ от телевизора, который наверняка валяется у вас в гостиной. На нём обычно есть кнопки вкл./выкл., кнопки перемещения по каналам вперёд/назад и кнопки с цифрами, переключающие на конкретный канал. Так вот, независимо от того, сколько раз вы будете нажимать кнопку с цифрой канала, например, 5, вы всегда будете попадать на 5й канал (отбросим для простоты возможность включения двузначных каналов). Поэтому эта операция идемпотентна. Однако, нажатие кнопки вкл./выкл. или кнопок перемещения по каналам вверх/вниз каждый раз будет приводить к разному результату, в зависимости от текущего состояния системы, и многократное нажатие приведёт в систему в другое (неизвестное) состояние. Поэтому эта операция не идемпотентна.
Почему это важно?
Концепция идемпотентности важна в распределённых системах, поскольку трудно получить действительно надежные гарантии того, сколько раз команда будет вызываться или обрабатываться.
Сети по своей сути ненадёжны, поэтому большинство распределённых систем не могут гарантировать однократную доставку или обработку сообщений, даже при использовании брокера сообщений, вроде RabbitMQ, Azure Service Bus или Amazon SQS. Большинство брокеров предлагают доставку «хотя бы раз», полагаясь на то, что логика повторяет обработку столько раз, сколько необходимо, пока не будет подтверждено, что обработка сообщения завершена.
Это означает, что, если сообщение не может быть обработано по какой-либо причине, оно будет отправлено повторно. Допустим, у нас есть обработчик сообщений, как ТВ, описанный выше. Если сообщение однозначно, как кнопка 5, то легко написать код обработки, независимо от того, сколько раз получено сообщение. Но если это сообщение «следующий канал», ситуация усложняется. Поэтому, если каждый обработчик сообщений в нашей системе идемпотентен, мы можем повторять любое сообщение столько раз, сколько захотим, и это не повлияет на общую корректность системы.
Почему бы не сделать все обработчики идемпотентными?
Это сложно. Допустим, нужно создать нового пользователя в БД и опубликовать событие UserCreated, чтобы другие части системы знали, что произошло. Псевдокод будет примерно таким:
Handle(CreateUser message)
{
DB.Store(message.User);
Bus.Publish(new UserCreated());
}
Теоретически - ОК, но что, если брокер сообщений не поддерживает транзакции? (Спойлер: большинство не поддерживают!) Если между этими двумя строками кода произойдет сбой, запись в базе данных будет создана, но сообщение UserCreated не будет опубликовано. При повторной отправке сообщения будет записана новая запись в БД, а затем сообщение будет опубликовано.
Эти дополнительные записи-зомби создаются в БД, большую часть времени дублируя действительные записи, без какого-либо сообщения в остальную часть системы. Это может быть трудно даже заметить, и ещё труднее потом навести порядок.
А если изменить порядок, и сначала отправлять сообщение, а потом сохранять пользователя? Теперь у нас обратная проблема. Мы создаём призрачное сообщение — объявление остальной части системы о событии, которое на самом деле не произошло. Если кто-нибудь попытается найти этого пользователя, то не найдёт, поскольку он не был создан. Но другие процессы продолжат работать на основе этого сообщения, возможно, выставляя счета, но не доставляя заказов!
При проектировании надёжной системы нужно думать, что произойдёт, если на какой-либо строке кода кто-то выдернет кабель питания сервера.
Окончание следует…
Источник: https://particular.net/blog/what-does-idempotent-mean
👍21
День 1960. #ЗаметкиНаПолях
Что Такое Идемпотентность в Программных Системах? Окончание
Начало
Как достичь идемпотентности?
Паттерн «Исходящие» (Outbox) обеспечивает согласованность, подобную базе данных, между операциями обмена сообщениями (как получением входящего сообщения, так и отправкой исходящих сообщений) и изменениями бизнес-данных в базе. Опираясь на транзакцию БД, мы превращаем гарантию доставки «хотя бы раз» брокера сообщений в гарантию ровно одной обработки.
Для реализации паттерна Outbox логика обработки сообщений разделена на две фазы:
1. Фаза обработки сообщения
Мы не отправляем исходящие сообщения немедленно брокеру сообщений, а храним их в памяти до завершения работы обработчика сообщений. На этом этапе мы сохраняем все накопленные исходящие сообщения в таблицу БД, используя ту же транзакцию, что и для записи бизнес-данных, и Id сообщения в качестве первичного ключа.
2. Фаза отправки
Все исходящие сообщения физически отправляются брокеру сообщений. Если всё идет хорошо, исходящие сообщения отправляются, а входящие обрабатываются. Но здесь ещё возможно возникновение проблемы и отправка не всех сообщений, что вынудит нас повторить попытку. Так возникнут дублирующие сообщения, но так и задумано.
Паттерн «Исходящие» связан с паттерном «Входящие», поэтому при обработке любого повторяющегося сообщения (или повторной попытке обработки сообщения, которое не удалось выполнить на этапе отправки), сначала извлекаются данные из таблицы исходящих сообщений. Если такое сообщение существует, это означает, что оно уже успешно обработано, надо пропустить этап обработки, и перейти к этапу отправки. Если сообщение является дубликатом, и исходящие сообщения уже отправлены, то и этап отправки также можно пропустить. На псевдокоде это выглядит так:
Используя этот шаблон, мы получаем идемпотентность на стороне обработки, когда вы можете отличить дубликат, просто взглянув на id сообщения.
Итого
Идемпотентность — важный атрибут распределённых систем, но его сложно реализовать надёжно. Ошибки, возникающие в результате неправильного выполнения действий, часто легко не заметить, а затем трудно диагностировать, поскольку они кажутся результатом состояний гонки, которые невозможно воспроизвести ни в каких контролируемых условиях.
Гораздо проще использовать такую инфраструктуру, как Outbox, которая может воспользоваться транзакцией локальной базы данных, уже используемой для хранения бизнес-данных, и использовать эту транзакцию для обеспечения согласованности между операциями входящего/исходящего обмена сообщениями и бизнес-данными, хранящимися в БД.
Источник: https://particular.net/blog/what-does-idempotent-mean
Что Такое Идемпотентность в Программных Системах? Окончание
Начало
Как достичь идемпотентности?
Паттерн «Исходящие» (Outbox) обеспечивает согласованность, подобную базе данных, между операциями обмена сообщениями (как получением входящего сообщения, так и отправкой исходящих сообщений) и изменениями бизнес-данных в базе. Опираясь на транзакцию БД, мы превращаем гарантию доставки «хотя бы раз» брокера сообщений в гарантию ровно одной обработки.
Для реализации паттерна Outbox логика обработки сообщений разделена на две фазы:
1. Фаза обработки сообщения
Мы не отправляем исходящие сообщения немедленно брокеру сообщений, а храним их в памяти до завершения работы обработчика сообщений. На этом этапе мы сохраняем все накопленные исходящие сообщения в таблицу БД, используя ту же транзакцию, что и для записи бизнес-данных, и Id сообщения в качестве первичного ключа.
2. Фаза отправки
Все исходящие сообщения физически отправляются брокеру сообщений. Если всё идет хорошо, исходящие сообщения отправляются, а входящие обрабатываются. Но здесь ещё возможно возникновение проблемы и отправка не всех сообщений, что вынудит нас повторить попытку. Так возникнут дублирующие сообщения, но так и задумано.
Паттерн «Исходящие» связан с паттерном «Входящие», поэтому при обработке любого повторяющегося сообщения (или повторной попытке обработки сообщения, которое не удалось выполнить на этапе отправки), сначала извлекаются данные из таблицы исходящих сообщений. Если такое сообщение существует, это означает, что оно уже успешно обработано, надо пропустить этап обработки, и перейти к этапу отправки. Если сообщение является дубликатом, и исходящие сообщения уже отправлены, то и этап отправки также можно пропустить. На псевдокоде это выглядит так:
var message = PeekMessage();
// проверка на дубликат
var outbox = DB.GetOutboxData(message.Id);
// обработка
if(outbox == null)
{
using(var trans = DB.StartTransaction())
{
var result = ExecuteHandler(message);
outbox = new OutboxData(message.Id, result);
DB.StoreOutboxData(outbox);
trans.Commit();
}
}
// отправка
if(!outbox.IsDispatched)
{
Bus.DispatchMessage(outbox);
DB.SetAsDispatched(message.Id);
}
Используя этот шаблон, мы получаем идемпотентность на стороне обработки, когда вы можете отличить дубликат, просто взглянув на id сообщения.
Итого
Идемпотентность — важный атрибут распределённых систем, но его сложно реализовать надёжно. Ошибки, возникающие в результате неправильного выполнения действий, часто легко не заметить, а затем трудно диагностировать, поскольку они кажутся результатом состояний гонки, которые невозможно воспроизвести ни в каких контролируемых условиях.
Гораздо проще использовать такую инфраструктуру, как Outbox, которая может воспользоваться транзакцией локальной базы данных, уже используемой для хранения бизнес-данных, и использовать эту транзакцию для обеспечения согласованности между операциями входящего/исходящего обмена сообщениями и бизнес-данными, хранящимися в БД.
Источник: https://particular.net/blog/what-does-idempotent-mean
👍14👎2
День 1961. #ЗаметкиНаПолях
Ожидает ли HttpClient всё Тело Ответа?
Если вы вызываете HttpClient.GetAsync или HttpClient.PostAsync, а затем ожидаете результат, ожидается получение только заголовков или всего тела ответа?
Сервер
Создадим простой сервер, который отправляет ответ с заголовком и телом. Тело будет отправляться частями, чтобы мы могли видеть, когда оно будет получено.
Таким образом, весь запрос занимает не менее 1 секунды. Напишем простой вызов этой конечной точки.
Клиент
Если выполнить этот код, мы увидим, что время ответа составляет около 1 секунды. Таким образом, await ожидает получения всего тела:
Теперь посмотрим, как можно не ждать тела. Используем опцию HttpCompletionOption.ResponseHeadersRead:
Мы добавили флаг в вызов GetAsync. Теперь время отклика значительно меньше:
Таким образом await ожидает только получения заголовков, и вы можете исследовать их сразу, как они будут получены. Тело всё ещё принимается в фоновом режиме. Если вы хотите дождаться получения тела, можно использовать метод ReadAsStringAsync:
Важно! Мы здесь используем using var response. Объект response продолжит удерживать ресурсы после await, поэтому необходимо удалять его как можно скорее.
Итого
Использование HttpCompletionOption.ResponseHeadersRead даёт выигрыш в производительности и памяти, и вы всё равно можете прочитать тело, если захотите. Но будьте осторожны с объектом ответа, так как он может по-прежнему удерживать ресурсы, что усложняет код. Так что это не должно быть выбором по умолчанию, если в этом нет необходимости.
Источник: https://steven-giesel.com/blogPost/e2c3bcba-4f81-42b0-9b25-060da5e819fa/does-an-httpclient-await-the-header-and-the-body
Ожидает ли HttpClient всё Тело Ответа?
Если вы вызываете HttpClient.GetAsync или HttpClient.PostAsync, а затем ожидаете результат, ожидается получение только заголовков или всего тела ответа?
Сервер
Создадим простой сервер, который отправляет ответ с заголовком и телом. Тело будет отправляться частями, чтобы мы могли видеть, когда оно будет получено.
app.MapGet("/", async ctx =>
{
await ctx.Response.WriteAsync("1");
await Task.Delay(500);
await ctx.Response.WriteAsync("2");
await Task.Delay(500);
await ctx.Response.WriteAsync("3");
await ctx.Response.CompleteAsync();
});
Таким образом, весь запрос занимает не менее 1 секунды. Напишем простой вызов этой конечной точки.
Клиент
using var client = new HttpClient();
// измерим время до получения ответа
var sw = Stopwatch.StartNew();
await client.GetAsync("https://localhost:5001");
Console.WriteLine(
$"Время отклика: {sw.ElapsedMilliseconds}мс");
Если выполнить этот код, мы увидим, что время ответа составляет около 1 секунды. Таким образом, await ожидает получения всего тела:
Время отклика: 1088мс
Теперь посмотрим, как можно не ждать тела. Используем опцию HttpCompletionOption.ResponseHeadersRead:
var sw = Stopwatch.StartNew();
await client.GetAsync("https://localhost:5001",
HttpCompletionOption.ResponseHeadersRead);
Console.WriteLine(
$"Время отклика: {sw.ElapsedMilliseconds}мс");
Мы добавили флаг в вызов GetAsync. Теперь время отклика значительно меньше:
Время отклика: 78мс
Таким образом await ожидает только получения заголовков, и вы можете исследовать их сразу, как они будут получены. Тело всё ещё принимается в фоновом режиме. Если вы хотите дождаться получения тела, можно использовать метод ReadAsStringAsync:
using var response =
await client.GetAsync("https://localhost:5001",
HttpCompletionOption.ResponseHeadersRead);
var body = await response.Content.ReadAsStringAsync();
Важно! Мы здесь используем using var response. Объект response продолжит удерживать ресурсы после await, поэтому необходимо удалять его как можно скорее.
Итого
Использование HttpCompletionOption.ResponseHeadersRead даёт выигрыш в производительности и памяти, и вы всё равно можете прочитать тело, если захотите. Но будьте осторожны с объектом ответа, так как он может по-прежнему удерживать ресурсы, что усложняет код. Так что это не должно быть выбором по умолчанию, если в этом нет необходимости.
Источник: https://steven-giesel.com/blogPost/e2c3bcba-4f81-42b0-9b25-060da5e819fa/does-an-httpclient-await-the-header-and-the-body
👍38
День 1962. #УрокиРазработки
Уроки 50 Лет Разработки ПО
Урок 11. Люди не просто «собирают» требования
Когда говорят «сбор требований», можно подумать о сборе цветов или грибов. С требованиями всё не так просто. Они редко существуют в сознании пользователей в сформированном виде, готовом для передачи бизнес-аналитику. Термин «выявление требований» точнее описывает, как разработчики сотрудничают с заинтересованными сторонами, чтобы понять, как те работают, и определить, какие возможности должна предоставлять будущая программная система. Задача бизнес-аналитика во время сбора информации - задавать правильные вопросы, стимулируя обсуждение и побуждать заинтересованные стороны выходить за рамки поверхностных и очевидных решений. При этом он не просто записывает всё, что ему говорят, а выявляет детали, помогая участникам структурировать знания.
Когда выявлять требования
В Agile-проектах требования намеренно рассматриваются небольшими порциями и ожидается, что набор требований будет расширяться в процессе разработки. Команда постепенно уточняет выявленные требования до уровня детализации, необходимого разработчикам и тестировщикам.
Контекст выявления
Документ о видении и масштабах проекта устанавливает бизнес-цели проекта, сферу охвата (что явно включено) и ограничения (что явно исключается). Чтобы начать процесс выявления требований, определите заинтересованные стороны, которые могут послужить источниками информации. Спланируйте стратегию сбора информации. Выбранные методы взаимодействия будут зависеть от доступности сторон и того, какие способы обсуждения являются наиболее подходящими и сколько времени стороны могут выделить на них. Планируйте каждую встречу, чтобы гарантировать получение необходимой информации.
Методы выявления
1. Собеседования
Собеседования 1-на-1 с заинтересованными сторонами позволяют углубиться в детали, не уходя от темы, но им не хватает синергетического взаимодействия, которое часто способствует появлению новых идей в групповых дискуссиях. В любом случае бизнес-аналитик должен подготовить список исследуемых тем и вопросов, которые необходимо задать.
2. Групповые семинары
Обычно лучше подходят для изучения требований пользователей. Но любые коллективные дискуссии склонны уходить в сторону, за запланированные рамки встречи. Опытный организатор удерживает участников в теме и обеспечивает получение полезной информации.
3. Наблюдение
Наблюдение за работой пользователей в привычной обстановке позволяет получить информацию, поделиться которой им бы и не пришло в голову, отвечая не вопросы бизнес-аналитика. Можно подметить проблемы и узкие места. Наблюдать особенно полезно для дизайна UI.
4. Анализ документов
Изучение документации к существующим продуктам помогает быстро освоиться в новой прикладной области, изучить бизнес-правила, корпоративные политики и отраслевые стандарты. Но такая информация обязательно должна проверяться на актуальность.
5. Опросы
Позволяют узнать мнение о текущих продуктах у большей части пользователей. Онлайн-опросы особенно полезны, когда нет прямого доступа к представителям пользователей. Опросы должны содержать минимально возможное количество вопросов, позволяющее узнать то, что нужно, не утомляя респондента.
6. Вики
Вики и другие инструменты для совместной работы позволяют собирать информацию и идеи среди более широкого круга людей, чем семинары. Недостаток их в необходимости фильтровать обсуждение, чтобы собрать действительно ценную информацию.
7. Прототипы
Людям трудно представить, каким может быть предлагаемое решение. Прототип делает требования более осязаемыми. Даже простые эскизы UI могут помочь получить наглядное представление. Но создавать прототипы в начале исследования требований рискованно, поскольку люди могут преждевременно зациклиться на конкретном (и, возможно, неидеальном) решении.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 2.
Уроки 50 Лет Разработки ПО
Урок 11. Люди не просто «собирают» требования
Когда говорят «сбор требований», можно подумать о сборе цветов или грибов. С требованиями всё не так просто. Они редко существуют в сознании пользователей в сформированном виде, готовом для передачи бизнес-аналитику. Термин «выявление требований» точнее описывает, как разработчики сотрудничают с заинтересованными сторонами, чтобы понять, как те работают, и определить, какие возможности должна предоставлять будущая программная система. Задача бизнес-аналитика во время сбора информации - задавать правильные вопросы, стимулируя обсуждение и побуждать заинтересованные стороны выходить за рамки поверхностных и очевидных решений. При этом он не просто записывает всё, что ему говорят, а выявляет детали, помогая участникам структурировать знания.
Когда выявлять требования
В Agile-проектах требования намеренно рассматриваются небольшими порциями и ожидается, что набор требований будет расширяться в процессе разработки. Команда постепенно уточняет выявленные требования до уровня детализации, необходимого разработчикам и тестировщикам.
Контекст выявления
Документ о видении и масштабах проекта устанавливает бизнес-цели проекта, сферу охвата (что явно включено) и ограничения (что явно исключается). Чтобы начать процесс выявления требований, определите заинтересованные стороны, которые могут послужить источниками информации. Спланируйте стратегию сбора информации. Выбранные методы взаимодействия будут зависеть от доступности сторон и того, какие способы обсуждения являются наиболее подходящими и сколько времени стороны могут выделить на них. Планируйте каждую встречу, чтобы гарантировать получение необходимой информации.
Методы выявления
1. Собеседования
Собеседования 1-на-1 с заинтересованными сторонами позволяют углубиться в детали, не уходя от темы, но им не хватает синергетического взаимодействия, которое часто способствует появлению новых идей в групповых дискуссиях. В любом случае бизнес-аналитик должен подготовить список исследуемых тем и вопросов, которые необходимо задать.
2. Групповые семинары
Обычно лучше подходят для изучения требований пользователей. Но любые коллективные дискуссии склонны уходить в сторону, за запланированные рамки встречи. Опытный организатор удерживает участников в теме и обеспечивает получение полезной информации.
3. Наблюдение
Наблюдение за работой пользователей в привычной обстановке позволяет получить информацию, поделиться которой им бы и не пришло в голову, отвечая не вопросы бизнес-аналитика. Можно подметить проблемы и узкие места. Наблюдать особенно полезно для дизайна UI.
4. Анализ документов
Изучение документации к существующим продуктам помогает быстро освоиться в новой прикладной области, изучить бизнес-правила, корпоративные политики и отраслевые стандарты. Но такая информация обязательно должна проверяться на актуальность.
5. Опросы
Позволяют узнать мнение о текущих продуктах у большей части пользователей. Онлайн-опросы особенно полезны, когда нет прямого доступа к представителям пользователей. Опросы должны содержать минимально возможное количество вопросов, позволяющее узнать то, что нужно, не утомляя респондента.
6. Вики
Вики и другие инструменты для совместной работы позволяют собирать информацию и идеи среди более широкого круга людей, чем семинары. Недостаток их в необходимости фильтровать обсуждение, чтобы собрать действительно ценную информацию.
7. Прототипы
Людям трудно представить, каким может быть предлагаемое решение. Прототип делает требования более осязаемыми. Даже простые эскизы UI могут помочь получить наглядное представление. Но создавать прототипы в начале исследования требований рискованно, поскольку люди могут преждевременно зациклиться на конкретном (и, возможно, неидеальном) решении.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 2.
👍7👎1
День 1963. #Шпаргалка #CSS
Единицы Размеров в CSS. Начало
Поговорим немного о фронтенде. Тем более, что разобраться с UI бывает очень непросто. Многие свойства CSS принимают числа в качестве значений. Кроме того, за ними часто следуют единицы измерения. Что такое px? Чем отличаются em и rem? И как определяются итоговые размеры?
В CSS есть два типа единиц: абсолютные и относительные.
Абсолютные единицы
Каким бы ни было число, оно именно так и рассчитывается в браузере, независимо от размера других элементов. Наиболее распространённое – пиксель (px) — наименьший строительный блок для отображения графики, основанный на разрешении. На экране с высоким разрешением пиксель будет меньше, чем на экране с низким.
Абсолютные значения предсказуемы. Но, если пользователь увеличивает масштаб страницы, то всё, что определено с абсолютным значением, соответственно увеличит свой абсолютный размер.
1. Длина
-
-
-
-
-
-
-
2. Углы
Хороши, например, для направления линейного градиента (linear-gradient) или поворота (rotate) элемента.
-
-
-
-
Например,
3. Время
Тут всё просто
-
-
Например,
4. Разрешение
Количество точек на единицу измерения. Чем меньше точек, тем более «пикселизированным» и размытым будет изображение. Отлично подходит для таргетинга стилей на определенные экраны в медиа-запросах.
-
-
-
Например,
Спецификация определяет значение infinite для медиа-запросов под экраны без ограничений разрешения.
Окончание следует…
Источник: https://css-tricks.com/css-length-units/
Единицы Размеров в CSS. Начало
Поговорим немного о фронтенде. Тем более, что разобраться с UI бывает очень непросто. Многие свойства CSS принимают числа в качестве значений. Кроме того, за ними часто следуют единицы измерения. Что такое px? Чем отличаются em и rem? И как определяются итоговые размеры?
В CSS есть два типа единиц: абсолютные и относительные.
Абсолютные единицы
Каким бы ни было число, оно именно так и рассчитывается в браузере, независимо от размера других элементов. Наиболее распространённое – пиксель (px) — наименьший строительный блок для отображения графики, основанный на разрешении. На экране с высоким разрешением пиксель будет меньше, чем на экране с низким.
Абсолютные значения предсказуемы. Но, если пользователь увеличивает масштаб страницы, то всё, что определено с абсолютным значением, соответственно увеличит свой абсолютный размер.
1. Длина
-
cm
– сантиметры (96px/2.54)-
mm
– миллиметры (1/10cm)-
Q
– четверть-миллиметры (1/40cm)-
in
– дюймы (2.54cm = 96px)-
pc
– пики (1/6in)-
pt
– точки (1/72in)-
px
– пиксели (1/96in)2. Углы
Хороши, например, для направления линейного градиента (linear-gradient) или поворота (rotate) элемента.
-
deg
– градусы (полный круг – 360deg)-
grad
– грады (круг – 400grad)-
rad
– радианы (круг - 2π ~ 6.2832rad)-
turn
– повороты (круг - 1turn)Например,
rotate(180deg)
3. Время
Тут всё просто
-
s
– секунды,-
ms
- миллисекундыНапример,
animation-duration: 2s
4. Разрешение
Количество точек на единицу измерения. Чем меньше точек, тем более «пикселизированным» и размытым будет изображение. Отлично подходит для таргетинга стилей на определенные экраны в медиа-запросах.
-
dpi
– точек на дюйм-
dpcm
– точек на сантиметр-
dppx
(или x
) – точек на пиксельНапример,
@media (min-resolution: 96dpi) { … }
Спецификация определяет значение infinite для медиа-запросов под экраны без ограничений разрешения.
Окончание следует…
Источник: https://css-tricks.com/css-length-units/
👍9
День 1964. #Шпаргалка #CSS
Единицы Размеров в CSS. Окончание
Начало. Абсолютные единицы
Относительные единицы
Значение относительной единицы зависит от размера чего-то ещё. Допустим, у нас есть элемент <div> с абсолютным значением высоты 200 пикселей. Эта высота никогда не изменится. Но если задать элементу относительную ширину в 50%, он займёт половину ширины страницы (либо половину ширины своего родителя). Относительное число действует как множитель для вычисления значения, в зависимости от того, относительно какого размера мы считаем.
1. Проценты
Используются, когда нет другого контекста для задания размера.
2. Относительно шрифта
-
-
Аналогично:
-
-
-
-
-
Большинство из этого требуется только для типографии. Однако, хорошей практикой является задавать размер шрифта в пикселях для элемента <html>, а для всех остальных элементов использовать относительные em и rem:
3. Относительно области просмотра (viewport – видимая часть страницы)
Эти величины всегда считаются относительно размеров страницы.
-
-
-
-
-
-
-
-
-
4. Относительно контейнера
Эти величины считаются в контейнер-запросах относительно размеров соответствующего контейнера.
-
-
-
-
-
Например,
Когда родительский элемент блока child превысит ширину в 30 символов, он станет занимать вместо полной ширины контейнера только половину его ширины.
Источник: https://css-tricks.com/css-length-units/
Единицы Размеров в CSS. Окончание
Начало. Абсолютные единицы
Относительные единицы
Значение относительной единицы зависит от размера чего-то ещё. Допустим, у нас есть элемент <div> с абсолютным значением высоты 200 пикселей. Эта высота никогда не изменится. Но если задать элементу относительную ширину в 50%, он займёт половину ширины страницы (либо половину ширины своего родителя). Относительное число действует как множитель для вычисления значения, в зависимости от того, относительно какого размера мы считаем.
1. Проценты
%
- относительно размера родительского элемента.Используются, когда нет другого контекста для задания размера.
2. Относительно шрифта
-
em
– элемент (относительно размера шрифта родительского элемента)-
rem
– корневой элемент (относительно размера шрифта элемента <html>)Аналогично:
-
ch
и rch
– ширина символа (отличается для каждого шрифта и у разных символов, кроме моноширинных шрифтов)-
lh
и rlh
– высота строки-
cap
и rcap
– высота заглавной буквы-
ic
и ric
– ширина иероглифа-
ex
и rex
– ширина буквы X.Большинство из этого требуется только для типографии. Однако, хорошей практикой является задавать размер шрифта в пикселях для элемента <html>, а для всех остальных элементов использовать относительные em и rem:
html {
/* Наследуется всеми элементами */
font-size: 18px;
}
.parent {
/* Изменяется при смене размера в `html` */
font-size: 1.1rem;
}
.child {
/* Изменяется при смене размера в `.parent` */
font-size: 0.9em;
}
3. Относительно области просмотра (viewport – видимая часть страницы)
Эти величины всегда считаются относительно размеров страницы.
-
vh
и vw
– высота и ширина (100vh – высота экрана)-
vmin
и vmax
– минимум и максимум между vh и vw соответственно-
lvh
и lvw
– «большие» высота и ширина (в полноэкранном режиме)-
lvb
и lvi
– эквиваленты lvh и lvw для блока и строки-
svh
и svw
– «маленькие» высота и ширина (когда отображаются UI браузера и экранная клавиатура)-
svb
и svi
– эквиваленты svh и svw для блока и строки-
dvh
и dvw
– «динамические» высота и ширина (изменяются, например, при отображении/скрытии экранной клавиатуры)-
dvb
и dvi
– эквиваленты dvh и dvw для блока и строки-
dvmin
и dvmax
– минимум и максимум между dvh/dvb и dvw/dvi соответственно. 4. Относительно контейнера
Эти величины считаются в контейнер-запросах относительно размеров соответствующего контейнера.
-
cqw
– ширина контейнера (100cqw – полная ширина)-
cqh
– высота контейнера-
cqi
– ширина строкового контейнера-
cqb
– ширина блокового контейнера-
cqmin
и cqmax
– минимум или максимум между cqi и cqbНапример,
.parent {
container-type: inline-size;
}
.child {
width: 100%;
@container (width > 30ch) {
.child {
width: 50cqi;
}
}
}
Когда родительский элемент блока child превысит ширину в 30 символов, он станет занимать вместо полной ширины контейнера только половину его ширины.
Источник: https://css-tricks.com/css-length-units/
👍13
День 1965. #ЧтоНовенького #CSharp13
Полуавтоматические Свойства
Полуавтоматические свойства позволяют вам добавлять логику в методы get и set, не создавая явно приватного поля как для полноценного свойства, а используя ключевое слово field.
Если это звучит знакомо, то вы не ошибаетесь. Эта функциональность давно была готова, и её пытались добавить в C# на протяжении нескольких последних версий. Проблема состояла в добавлении нового ключевого слова в язык, т.е. добавлении ломающего изменения.
Автоматические свойства
Автоматические свойства появились очень давно и используются повсеместно:
Этот код за кулисами создаёт приватное поле и два метода для получения и задания его значения. Т.е. следующий код эквивалентен коду выше:
Но что, если мы хотим добавить какую-то логику в метод get или set автосвойства? К примеру, мы хотим, чтобы имя всегда задавалось без лишних пробелов. До сих пор нам ничего не оставалось, кроме как отказаться от автосвойства и использовать полноценное свойство, явно создавая поле для него:
Полуавтоматические свойства
Начиная с С#13 мы сможем использовать для этого ключевое слово field, и не создавать поле явно:
Интересно, что, даже если вам нужно изменить только set, то придётся реализовать и get (пусть и в таком элементарном виде). То есть, его нельзя оставить в виде
Очевидно, что добавление нового ключевого слова может сломать чей-то существующий код. Если в вашем коде использовалось поле с названием field, то в такой ситуации будет не понятно, нужно обращаться к этому полю, либо к неявному полю для свойства Name.
Microsoft годами пыталась избегать ломающих изменений, в частности при вводе новых ключевых слов. Раньше они создавали сложные правила для разрешения этих конфликтов. Но теперь решили пойти другим путём. На примере этой функции они хотят протестировать инструмент «раннего предупреждения» о ломающем изменении. Теперь, когда вы обновляете .NET SDK на новую версию (при этом используя старую версию .NET в проектах), анализатор кода в таких случаях будет выдавать предупреждение, что этот код не будет работать в новой версии языка и предлагать автоматический рефакторинг кода под новую версию.
В этом случае для обращения к полю field из свойства нужно будет добавить @:
Источник: https://www.youtube.com/watch?v=3jb9Du9pMes
Полуавтоматические Свойства
Полуавтоматические свойства позволяют вам добавлять логику в методы get и set, не создавая явно приватного поля как для полноценного свойства, а используя ключевое слово field.
Если это звучит знакомо, то вы не ошибаетесь. Эта функциональность давно была готова, и её пытались добавить в C# на протяжении нескольких последних версий. Проблема состояла в добавлении нового ключевого слова в язык, т.е. добавлении ломающего изменения.
Автоматические свойства
Автоматические свойства появились очень давно и используются повсеместно:
public class Test
{
public string Name { get; set; }
}
Этот код за кулисами создаёт приватное поле и два метода для получения и задания его значения. Т.е. следующий код эквивалентен коду выше:
csharp
public class Test
{
private string _name;
public string get_Name()
{
return _name;
}
public void set_Name(string name)
{
_name = name;
}
}
Но что, если мы хотим добавить какую-то логику в метод get или set автосвойства? К примеру, мы хотим, чтобы имя всегда задавалось без лишних пробелов. До сих пор нам ничего не оставалось, кроме как отказаться от автосвойства и использовать полноценное свойство, явно создавая поле для него:
private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value.Trim();
}
}
Полуавтоматические свойства
Начиная с С#13 мы сможем использовать для этого ключевое слово field, и не создавать поле явно:
public string Name {
get => field;
set => field = value.Trim();
}
Интересно, что, даже если вам нужно изменить только set, то придётся реализовать и get (пусть и в таком элементарном виде). То есть, его нельзя оставить в виде
get;
. Возможно, к релизу это исправят.Очевидно, что добавление нового ключевого слова может сломать чей-то существующий код. Если в вашем коде использовалось поле с названием field, то в такой ситуации будет не понятно, нужно обращаться к этому полю, либо к неявному полю для свойства Name.
Microsoft годами пыталась избегать ломающих изменений, в частности при вводе новых ключевых слов. Раньше они создавали сложные правила для разрешения этих конфликтов. Но теперь решили пойти другим путём. На примере этой функции они хотят протестировать инструмент «раннего предупреждения» о ломающем изменении. Теперь, когда вы обновляете .NET SDK на новую версию (при этом используя старую версию .NET в проектах), анализатор кода в таких случаях будет выдавать предупреждение, что этот код не будет работать в новой версии языка и предлагать автоматический рефакторинг кода под новую версию.
В этом случае для обращения к полю field из свойства нужно будет добавить @:
private string field;
public string Field {
get => @field;
set => @field = value.Trim();
}
Источник: https://www.youtube.com/watch?v=3jb9Du9pMes
👍31
День 1966. #ЗаметкиНаПолях
Безопасны Мои LINQ Запросы в EF?
Задумывались ли вы когда-нибудь о том, подвержены ли ваши LINQ-запросы в EF атакам с использованием SQL-инъекции? Т.к. вы либо используете данные прямо из текстового поля, либо вставляете всё, что вернул API в базу?
Ну, во-первых, нужно всегда проверять и экранировать вводимые данные. Но, допустим, вы этого не сделали, и …?
Хорошая новость: Entity Framework экранирует ввод. Поэтому, если у вас есть что-то вроде этого:
Результирующий SQL будет вроде следующего:
И это хорошо, потому что атака SQL-инъекцией не пройдёт, т.к.
Это не сработает, если вы используете чистые SQL-запросы. Поэтому, такой код:
может быть подвержен атакам SQL-инъекцией.
FromSql (до EF Core 7 - FromSqlInterpolated)
FromSql – это более безопасный способ использовать чистый SQL. Метод – часть пакета Microsoft.EntityFrameworkCore.Relational. Вот разница коротко:
Хотя они выглядят одинаково, важна сигнатура методов:
Если вы хотите выполнить произвольный SQL-запрос, вы можете использовать
Итого
Используйте
Источник: https://steven-giesel.com/blogPost/35ec8819-220a-42bc-9224-a812ec358434/are-my-ef-linq-to-sql-queries-safe
Безопасны Мои LINQ Запросы в EF?
Задумывались ли вы когда-нибудь о том, подвержены ли ваши LINQ-запросы в EF атакам с использованием SQL-инъекции? Т.к. вы либо используете данные прямо из текстового поля, либо вставляете всё, что вернул API в базу?
Ну, во-первых, нужно всегда проверять и экранировать вводимые данные. Но, допустим, вы этого не сделали, и …?
Хорошая новость: Entity Framework экранирует ввод. Поэтому, если у вас есть что-то вроде этого:
var userInput = "Jon \"OR 1 = 1";
var evil = await myContext
.People
.Where(p => p.Name === userInput)
.ToListAsync();
Результирующий SQL будет вроде следующего:
SELECT "p"."Id", "p"."Name"
FROM "People" as "p"
WHERE "p"."Name" = 'Jon "OR 1 = 1'
И это хорошо, потому что атака SQL-инъекцией не пройдёт, т.к.
OR 1 = 1
будет рассматриваться как строка, а не как команда SQL.Это не сработает, если вы используете чистые SQL-запросы. Поэтому, такой код:
var userInput = "Jon \"OR 1 = 1";
var evil = await myContext
.People
.FromSqlRaw(
$"SELECT * FROM People WHERE Name = '{userInput}'")
.ToListAsync();
может быть подвержен атакам SQL-инъекцией.
FromSql (до EF Core 7 - FromSqlInterpolated)
FromSql – это более безопасный способ использовать чистый SQL. Метод – часть пакета Microsoft.EntityFrameworkCore.Relational. Вот разница коротко:
var evil = await myContext.
.People
.FromSqlRaw(
$"SELECT * FROM People WHERE Name = {userInput}")
.ToListAsync();
// или
var notSoEvil = await myContext.
.People
.FromSql(
$"SELECT * FROM People WHERE Name = {userInput}")
.ToListAsync();
Хотя они выглядят одинаково, важна сигнатура методов:
FromSqlRaw
принимает string
, а FromSql
— FormattableString
. FormattableString представляет собой строку с заполнителями для параметров. Так EF знает, что такое userInput, и сможет правильно его экранировать.Если вы хотите выполнить произвольный SQL-запрос, вы можете использовать
ExecuteSql
на объекте Database (вместо DbSet<TYourEntity>).Итого
Используйте
FromSql
(или FromSqlInterpolated
). В некоторых редких случаях могут быть проблемы форматирования интерполированных строк, но они редки. Если вы столкнётесь с ними, можете использовать FromSqlRaw
, но вы должны осознавать риски.Источник: https://steven-giesel.com/blogPost/35ec8819-220a-42bc-9224-a812ec358434/are-my-ef-linq-to-sql-queries-safe
👍32
День 1967. #ЗаметкиНаПолях
Вы Пожалеете, что Использовали Естественные Ключи
В Дании автомобили проходят обязательный техосмотр раз в 2 года. Несколько лет назад механик, проводивший осмотр, сообщил мне, что VIN-номер моей машины в их системе неправильный. Это заставило меня нервничать. Неужели я случайно купил украденную машину?
Но механик просто подошел к компьютеру, чтобы исправить ошибку. Тут меня охватило другое беспокойство. Поскольку VIN является очевидным кандидатом на роль естественного ключа, я уже перебирал в голове всевозможные каскадные эффекты, которые в итоге приведут к тому, что официальные отчёты перестанут признавать, что машина моя. Оказалось, автор этого ПО, знал, что делал, потому что механик просто изменил номер, и всё.
Уникальность
Хороший архитектор ПО должен бросать вызов основополагающим предположениям. Допустим, вы отказались от синтетического ключа. Является ли выбранный естественный ключ (поле или сочетание полей) уникальным? Допустим, название города уникально в пределах региона. Но что, если ПО расширится до использования по всей стране? А если на несколько стран?
Идентичность
Хорошо, для таблицы городов синтетический ключ - лучший выбор, это довольно очевидно. А как насчёт, «естественных» естественных ключей? Примером может быть VIN автомобиля. Это уже определённый код, и он, вероятно, берётся из какой-то базы. А номер паспорта (или аналогичный номер в других странах)?
Если вы разрабатываете базу, которая уже содержит такой личный идентификационный номер, у вас может возникнуть соблазн использовать его в качестве естественного ключа. Это уже ключ где-то ещё, поэтому он гарантированно уникален, верно?
Да, номер может однозначно идентифицировать человека, но обратное может быть неверным. Лицо может иметь более одного идентификационного номера. По крайней мере, с течением времени. Например, люди меняют паспорта. У них не может быть более одного одновременно, но будет более одного за жизнь.
Даже если существующие ключи гарантированно уникальны, нельзя предполагать, что уникальность приводит к взаимно однозначному соответствию между ключом и объектом. Если вы используете внешний уникальный ключ, вы можете потерять данные об объектах, которые пытаетесь отслеживать.
Технические ошибки
Наконец, даже если вы нашли естественный ключ, который гарантированно уникален и отслеживает реальный объект, который вы хотите отслеживать, есть последний аргумент против использования внешнего ключа в вашей системе: ошибки ввода данных.
Возьмем, к примеру, историю о VIN-номере моей машины. Механик, заметивший несоответствие, явно истолковал это как техническую ошибку.
Рано или поздно в ваших данных появятся ошибки. Либо технические, либо опечатки пользователей, либо ошибки преобразования данных при импорте из внешней системы или после обновления. Система должна быть спроектирована так, чтобы можно было вносить исправления в данные. Сюда входит исправление внешних ключей, таких как VIN-номера, правительственные идентификаторы и т.д. Поэтому вы не можете использовать такие ключи в качестве ключей БД в своей системе.
Итого
Стоит ли использовать естественные ключи при проектировании БД? Мой опыт подсказывает мне, что нет. В конечном счёте, независимо от того, насколько вы уверены в том, что естественный ключ стабилен и правильно отслеживает объект, который должен отслеживать, будут возникать ошибки в данных. Сюда входят ошибки в этих естественных ключах. Вы должны иметь возможность исправлять такие ошибки, не теряя при этом зависимых объектов. Вы пожалеете об использовании естественных ключей. Используйте синтетические ключи.
Источник: https://blog.ploeh.dk/2024/06/03/youll-regret-using-natural-keys/
Автор оригинала: Mark Seemann
Вы Пожалеете, что Использовали Естественные Ключи
В Дании автомобили проходят обязательный техосмотр раз в 2 года. Несколько лет назад механик, проводивший осмотр, сообщил мне, что VIN-номер моей машины в их системе неправильный. Это заставило меня нервничать. Неужели я случайно купил украденную машину?
Но механик просто подошел к компьютеру, чтобы исправить ошибку. Тут меня охватило другое беспокойство. Поскольку VIN является очевидным кандидатом на роль естественного ключа, я уже перебирал в голове всевозможные каскадные эффекты, которые в итоге приведут к тому, что официальные отчёты перестанут признавать, что машина моя. Оказалось, автор этого ПО, знал, что делал, потому что механик просто изменил номер, и всё.
Уникальность
Хороший архитектор ПО должен бросать вызов основополагающим предположениям. Допустим, вы отказались от синтетического ключа. Является ли выбранный естественный ключ (поле или сочетание полей) уникальным? Допустим, название города уникально в пределах региона. Но что, если ПО расширится до использования по всей стране? А если на несколько стран?
Идентичность
Хорошо, для таблицы городов синтетический ключ - лучший выбор, это довольно очевидно. А как насчёт, «естественных» естественных ключей? Примером может быть VIN автомобиля. Это уже определённый код, и он, вероятно, берётся из какой-то базы. А номер паспорта (или аналогичный номер в других странах)?
Если вы разрабатываете базу, которая уже содержит такой личный идентификационный номер, у вас может возникнуть соблазн использовать его в качестве естественного ключа. Это уже ключ где-то ещё, поэтому он гарантированно уникален, верно?
Да, номер может однозначно идентифицировать человека, но обратное может быть неверным. Лицо может иметь более одного идентификационного номера. По крайней мере, с течением времени. Например, люди меняют паспорта. У них не может быть более одного одновременно, но будет более одного за жизнь.
Даже если существующие ключи гарантированно уникальны, нельзя предполагать, что уникальность приводит к взаимно однозначному соответствию между ключом и объектом. Если вы используете внешний уникальный ключ, вы можете потерять данные об объектах, которые пытаетесь отслеживать.
Технические ошибки
Наконец, даже если вы нашли естественный ключ, который гарантированно уникален и отслеживает реальный объект, который вы хотите отслеживать, есть последний аргумент против использования внешнего ключа в вашей системе: ошибки ввода данных.
Возьмем, к примеру, историю о VIN-номере моей машины. Механик, заметивший несоответствие, явно истолковал это как техническую ошибку.
Рано или поздно в ваших данных появятся ошибки. Либо технические, либо опечатки пользователей, либо ошибки преобразования данных при импорте из внешней системы или после обновления. Система должна быть спроектирована так, чтобы можно было вносить исправления в данные. Сюда входит исправление внешних ключей, таких как VIN-номера, правительственные идентификаторы и т.д. Поэтому вы не можете использовать такие ключи в качестве ключей БД в своей системе.
Итого
Стоит ли использовать естественные ключи при проектировании БД? Мой опыт подсказывает мне, что нет. В конечном счёте, независимо от того, насколько вы уверены в том, что естественный ключ стабилен и правильно отслеживает объект, который должен отслеживать, будут возникать ошибки в данных. Сюда входят ошибки в этих естественных ключах. Вы должны иметь возможность исправлять такие ошибки, не теряя при этом зависимых объектов. Вы пожалеете об использовании естественных ключей. Используйте синтетические ключи.
Источник: https://blog.ploeh.dk/2024/06/03/youll-regret-using-natural-keys/
Автор оригинала: Mark Seemann
👍24
День 1968. #ЗаметкиНаПолях
Различия Между Span и Memory в C#
Сегодня разберём особенности типов Span и Memory в .NET, и когда что использовать.
Span<T>
Это ref-структура в .NET, представляющая собой доступ к непрерывной области памяти. Т.е. Span<T> — это всего лишь представление блока памяти, а не способ выделить память.
Span<T> может иметь несколько источников блока памяти:
- массив T[] (или его фрагмент)
- Memory<T>
- неуправляемый указатель
- результат stackalloc
Например:
Span<T> всегда располагается в стеке и хранит только указатель на уже выделенный ссылочный тип и не выделяет новую управляемую память в куче. Span<T> нельзя упаковать или назначить переменным типа Object, Dynamic или интерфейсам. Он также не может быть полем ссылочного типа.
Использование Span<T> не требует вычисления начала указателя на ссылочный тип и смещения, поскольку эта информация уже содержится в Span<T>. Это делает вычисления с ним очень быстрыми. Более того, поскольку Span<T> не выделяет дополнительную память в куче, сборщик мусора работает быстрее, что повышает производительность всего приложения.
Memory<T>
Как и Span<T> представляет собой доступ к непрерывной области памяти, однако является структурой. Memory<T> можно разместить как в управляемой куче, так и в стеке, использовать в качестве поля в классе, а также совместно с await и yield.
Свойство Span возвращает Span<T>, что позволяет использовать Memory<T> как Span<T> в рамках одного метода. В этом смысле Memory<T> иногда называют фабрикой Span’ов.
Рекомендации
- Как правило, следует использовать Span<T> в качестве параметра для синхронного API, когда это возможно.
- Если буфер памяти должен быть доступен только для чтения, можно использовать ReadOnlySpan<T> и ReadOnlyMemory<T>.
- Если метод имеет параметр Memory<T> и возвращает void, не следует использовать этот экземпляр Memory<T> после завершения выполнения метода. Аналогично, если метод возвращает Task, не следует использовать экземпляр после завершения задачи.
Итого
Оба типа значительно повышают производительность приложений и обеспечивают безопасность памяти при работе с неуправляемыми ресурсами, важно понимать их последствия и ограничения.
Span<T> и Memory<T> - это представления блока памяти, которые предназначены для предотвращения копирования памяти или выделения большего количества памяти, чем необходимо, для управляемой кучи.
Для быстрых локальных вычислений и во избежание выделения ненужной памяти лучшим выбором является Span. Но, когда нужно передать его в качестве аргумента или использовать в асинхронном методе, приходится использовать Memory, который не имеет ограничений Span’а.
Источник: https://code-maze.com/csharp-differences-between-span-and-memory/
Различия Между Span и Memory в C#
Сегодня разберём особенности типов Span и Memory в .NET, и когда что использовать.
Span<T>
Это ref-структура в .NET, представляющая собой доступ к непрерывной области памяти. Т.е. Span<T> — это всего лишь представление блока памяти, а не способ выделить память.
Span<T> может иметь несколько источников блока памяти:
- массив T[] (или его фрагмент)
- Memory<T>
- неуправляемый указатель
- результат stackalloc
Например:
int[] data = [1, 2, 3, 4, 5, 6];
var span = data.AsSpan().Slice(2, 1);
Span<T> всегда располагается в стеке и хранит только указатель на уже выделенный ссылочный тип и не выделяет новую управляемую память в куче. Span<T> нельзя упаковать или назначить переменным типа Object, Dynamic или интерфейсам. Он также не может быть полем ссылочного типа.
Использование Span<T> не требует вычисления начала указателя на ссылочный тип и смещения, поскольку эта информация уже содержится в Span<T>. Это делает вычисления с ним очень быстрыми. Более того, поскольку Span<T> не выделяет дополнительную память в куче, сборщик мусора работает быстрее, что повышает производительность всего приложения.
Memory<T>
Как и Span<T> представляет собой доступ к непрерывной области памяти, однако является структурой. Memory<T> можно разместить как в управляемой куче, так и в стеке, использовать в качестве поля в классе, а также совместно с await и yield.
Свойство Span возвращает Span<T>, что позволяет использовать Memory<T> как Span<T> в рамках одного метода. В этом смысле Memory<T> иногда называют фабрикой Span’ов.
Рекомендации
- Как правило, следует использовать Span<T> в качестве параметра для синхронного API, когда это возможно.
- Если буфер памяти должен быть доступен только для чтения, можно использовать ReadOnlySpan<T> и ReadOnlyMemory<T>.
- Если метод имеет параметр Memory<T> и возвращает void, не следует использовать этот экземпляр Memory<T> после завершения выполнения метода. Аналогично, если метод возвращает Task, не следует использовать экземпляр после завершения задачи.
Итого
Оба типа значительно повышают производительность приложений и обеспечивают безопасность памяти при работе с неуправляемыми ресурсами, важно понимать их последствия и ограничения.
Span<T> и Memory<T> - это представления блока памяти, которые предназначены для предотвращения копирования памяти или выделения большего количества памяти, чем необходимо, для управляемой кучи.
Для быстрых локальных вычислений и во избежание выделения ненужной памяти лучшим выбором является Span. Но, когда нужно передать его в качестве аргумента или использовать в асинхронном методе, приходится использовать Memory, который не имеет ограничений Span’а.
Источник: https://code-maze.com/csharp-differences-between-span-and-memory/
👍26