День 1822. #Карьера
6 Факторов, Определяющих Победите Вы или Провалитесь. Начало
Во всех наших начинаниях успех – это желаемое конечное состояние. Он приносит воодушевление, радость и гордость. А неудача разочаровывает и может даже лишить некоторых мотивации пытаться достичь своих целей. Не существует единого ключа к успеху, т.к. он часто является сочетанием множества различных факторов: не только ваших усилий, но и обстоятельств, опыта и удачи.
Вот 6 факторов, которые не гарантируют успеха, но определённо помогут изменить баланс в вашу пользу.
1. Ясность критериев успеха
Если иметь лишь смутное представление о том, что для вас значит успех, может быть сложно определить, достигли ли вы своей цели. Достижение успеха начинается с определения того, что он для вас значит: что для вас важно, чего вы хотите достичь, почему это важно, как вы можете это измерить?
Определите успех, ответив на следующие вопросы:
- Как выглядит успех?
- Что изменится, когда вы достигнете этого?
- Что останется прежним, если вы не достигнете своей цели?
- Какие показатели, параметры или другие данные необходимы для отслеживания вашего прогресса?
- Как узнать, находитесь ли вы на правильном пути, а когда отклонились от него?
Будьте ясны, кратки и конкретны. Расплывчатые определения, такие как счастливая семья, успешная карьера, финансовая безопасность, только заставят вас чувствовать себя застрявшим, несчастным и неудовлетворенным.
2. Последовательность в действиях
Нужно работать над своим планом каждый день, даже когда тяжело и не хочется. Последовательность превращает небольшие ежедневные достижения в большие результаты.
Вот несколько важных практик, которые помогут достичь ежедневных целей:
- Разбейте цель на небольшие задачи. Маленькие шаги отключают систему сигнализации мозга, которая сопротивляется переменам и боится их.
- Работая над задачей, используйте «помидорный график».
- Запланируйте самые важные задачи на пик вашей умственной энергии.
- В конце каждого дня выделяйте 15–20 минут, чтобы поразмышлять о прогрессе и определить, как его можно улучшить.
3. Реакция на неожиданные события или результаты
Неожиданности, изменение обстоятельств или отсутствие желаемых результатов, несмотря на все усилия, могут выбить вас из колеи. Дела будут трудными. Возникнут новые проблемы. Вместо того, чтобы сдаваться, вы должны научиться отряхиваться, вставать и продолжать двигаться вперёд.
Разрешите себе чувствовать разочарование, но не позволяйте временным неудачам превратиться в постоянные оправдания.
При столкновении с препятствием:
- Попробуйте другую стратегию.
- Поэкспериментируйте с несколькими вариантами, чтобы определить тот, который работает.
- Изучите новые способы ведения дел.
- Развивайтесь всесторонне, чтобы получать идеи из других областей знаний.
Когда вы продолжаете искать способы изменить ситуацию к лучшему, у вас есть шанс их найти. Когда вы прекращаете поиск, предполагая, что их невозможно найти, вы признаёте поражение.
Окончание следует…
Источник: https://betterprogramming.pub/6-factors-that-determine-whether-you-will-succeed-or-fail-ae1dfe446e2b
6 Факторов, Определяющих Победите Вы или Провалитесь. Начало
Во всех наших начинаниях успех – это желаемое конечное состояние. Он приносит воодушевление, радость и гордость. А неудача разочаровывает и может даже лишить некоторых мотивации пытаться достичь своих целей. Не существует единого ключа к успеху, т.к. он часто является сочетанием множества различных факторов: не только ваших усилий, но и обстоятельств, опыта и удачи.
Вот 6 факторов, которые не гарантируют успеха, но определённо помогут изменить баланс в вашу пользу.
1. Ясность критериев успеха
Если иметь лишь смутное представление о том, что для вас значит успех, может быть сложно определить, достигли ли вы своей цели. Достижение успеха начинается с определения того, что он для вас значит: что для вас важно, чего вы хотите достичь, почему это важно, как вы можете это измерить?
Определите успех, ответив на следующие вопросы:
- Как выглядит успех?
- Что изменится, когда вы достигнете этого?
- Что останется прежним, если вы не достигнете своей цели?
- Какие показатели, параметры или другие данные необходимы для отслеживания вашего прогресса?
- Как узнать, находитесь ли вы на правильном пути, а когда отклонились от него?
Будьте ясны, кратки и конкретны. Расплывчатые определения, такие как счастливая семья, успешная карьера, финансовая безопасность, только заставят вас чувствовать себя застрявшим, несчастным и неудовлетворенным.
2. Последовательность в действиях
Нужно работать над своим планом каждый день, даже когда тяжело и не хочется. Последовательность превращает небольшие ежедневные достижения в большие результаты.
Вот несколько важных практик, которые помогут достичь ежедневных целей:
- Разбейте цель на небольшие задачи. Маленькие шаги отключают систему сигнализации мозга, которая сопротивляется переменам и боится их.
- Работая над задачей, используйте «помидорный график».
- Запланируйте самые важные задачи на пик вашей умственной энергии.
- В конце каждого дня выделяйте 15–20 минут, чтобы поразмышлять о прогрессе и определить, как его можно улучшить.
3. Реакция на неожиданные события или результаты
Неожиданности, изменение обстоятельств или отсутствие желаемых результатов, несмотря на все усилия, могут выбить вас из колеи. Дела будут трудными. Возникнут новые проблемы. Вместо того, чтобы сдаваться, вы должны научиться отряхиваться, вставать и продолжать двигаться вперёд.
Разрешите себе чувствовать разочарование, но не позволяйте временным неудачам превратиться в постоянные оправдания.
При столкновении с препятствием:
- Попробуйте другую стратегию.
- Поэкспериментируйте с несколькими вариантами, чтобы определить тот, который работает.
- Изучите новые способы ведения дел.
- Развивайтесь всесторонне, чтобы получать идеи из других областей знаний.
Когда вы продолжаете искать способы изменить ситуацию к лучшему, у вас есть шанс их найти. Когда вы прекращаете поиск, предполагая, что их невозможно найти, вы признаёте поражение.
Окончание следует…
Источник: https://betterprogramming.pub/6-factors-that-determine-whether-you-will-succeed-or-fail-ae1dfe446e2b
👍9
День 1823. #Карьера
6 Факторов, Определяющих Победите Вы или Провалитесь. Окончание
Начало
4. История, которую вы рассказываете себе
Ваш разум — это машина, создающая смыслы. Ему нравится объяснять вещи, придумывая истории, которые соответствуют вашим убеждениям и ожиданиям.
Когда вы чего-то достигаете, учитываете ли вы роль внутренних факторов, таких как ваши усилия, навыки и упорство, которые способствовали этому успеху, или вы игнорируете свои достижения, приписывая их внешним факторам, таким как удача, другие люди или стечение обстоятельств? Аналогично, когда вы терпите неудачу, как вы реагируете? Берёте ли вы на себя ответственность и анализируете своё поведение или обвиняете внешние обстоятельства или других людей?
Ваши убеждения об успехе и неудаче существенно влияют на восприятие, чувства и, в итоге, на то, как вы действуете. Когда вы не осознаёте свои сильные стороны, которые сделали успех возможным, или чувствуете себя неспособным противостоять неудачам, даже когда всё находится вне вашего контроля, ваши самоограничивающие убеждения мешают вашему росту.
Чтобы оставаться в контакте с реальностью:
- Определите вещи, которые находятся под вашим контролем, и те, которые находятся за его пределами.
- Расширьте круг своего влияния, работая над вещами, находящимися под вашим контролем.
- Перестаньте тратить время и энергию на вещи, находящиеся вне вашего контроля.
5. Возможность отделить сигнал от шума
Работая над целью, вы обязательно получите много обратной связи. Однако большая её часть — это шум: она не помогает достичь чего-то значительного или отвлекает вас от целей. Но среди шума скрывается тот редкий совет, мудрость или знание, которые помогут двигаться вперёд и приблизиться к цели.
Чтобы добиться успеха, нужно понять, что другие могут поделиться ценной обратной связью и научиться конструктивно воспринимать критику:
- Не принимайте обратную связь на личный счёт и не привязывайте её к своей ценности и значимости.
- Не отказывайтесь признавать пробелы в своих знаниях.
- Не относитесь к другим как к неполноценным и не отказывайтесь доверять их суждениям.
- Не позволяйте своему эго мешать.
Критика может быть неприятна, но она необходима. Она выполняет ту же функцию, что и боль - привлекает внимание к проблеме.
6. Получение нужной помощи в нужное время
У всех успешных людей есть одна общая черта: они не уклоняются от обращения за помощью, когда она им нужна. Не обращение за помощью, когда она вам нужна, не только мешает вам получить идеи и советы для продвижения вперёд, но и является глупой ошибкой. Никто не будет смотреть на вас свысока, если вы попросите о помощи. Никто не будет подвергать сомнению ваши способности. Это показывает, что вы верите, что ответ существует, и готовы сделать всё возможное, чтобы получить его.
Когда обращаетесь за помощью:
- Прямо попросите о помощи. Не думайте, что другие могут читать ваши мысли.
- Излагайте проблему конкретно и чётко.
Относитесь к своей уязвимости как к силе, и вы удивитесь, увидев, как много людей готовы вам помочь.
Источник: https://betterprogramming.pub/6-factors-that-determine-whether-you-will-succeed-or-fail-ae1dfe446e2b
6 Факторов, Определяющих Победите Вы или Провалитесь. Окончание
Начало
4. История, которую вы рассказываете себе
Ваш разум — это машина, создающая смыслы. Ему нравится объяснять вещи, придумывая истории, которые соответствуют вашим убеждениям и ожиданиям.
Когда вы чего-то достигаете, учитываете ли вы роль внутренних факторов, таких как ваши усилия, навыки и упорство, которые способствовали этому успеху, или вы игнорируете свои достижения, приписывая их внешним факторам, таким как удача, другие люди или стечение обстоятельств? Аналогично, когда вы терпите неудачу, как вы реагируете? Берёте ли вы на себя ответственность и анализируете своё поведение или обвиняете внешние обстоятельства или других людей?
Ваши убеждения об успехе и неудаче существенно влияют на восприятие, чувства и, в итоге, на то, как вы действуете. Когда вы не осознаёте свои сильные стороны, которые сделали успех возможным, или чувствуете себя неспособным противостоять неудачам, даже когда всё находится вне вашего контроля, ваши самоограничивающие убеждения мешают вашему росту.
Чтобы оставаться в контакте с реальностью:
- Определите вещи, которые находятся под вашим контролем, и те, которые находятся за его пределами.
- Расширьте круг своего влияния, работая над вещами, находящимися под вашим контролем.
- Перестаньте тратить время и энергию на вещи, находящиеся вне вашего контроля.
5. Возможность отделить сигнал от шума
Работая над целью, вы обязательно получите много обратной связи. Однако большая её часть — это шум: она не помогает достичь чего-то значительного или отвлекает вас от целей. Но среди шума скрывается тот редкий совет, мудрость или знание, которые помогут двигаться вперёд и приблизиться к цели.
Чтобы добиться успеха, нужно понять, что другие могут поделиться ценной обратной связью и научиться конструктивно воспринимать критику:
- Не принимайте обратную связь на личный счёт и не привязывайте её к своей ценности и значимости.
- Не отказывайтесь признавать пробелы в своих знаниях.
- Не относитесь к другим как к неполноценным и не отказывайтесь доверять их суждениям.
- Не позволяйте своему эго мешать.
Критика может быть неприятна, но она необходима. Она выполняет ту же функцию, что и боль - привлекает внимание к проблеме.
6. Получение нужной помощи в нужное время
У всех успешных людей есть одна общая черта: они не уклоняются от обращения за помощью, когда она им нужна. Не обращение за помощью, когда она вам нужна, не только мешает вам получить идеи и советы для продвижения вперёд, но и является глупой ошибкой. Никто не будет смотреть на вас свысока, если вы попросите о помощи. Никто не будет подвергать сомнению ваши способности. Это показывает, что вы верите, что ответ существует, и готовы сделать всё возможное, чтобы получить его.
Когда обращаетесь за помощью:
- Прямо попросите о помощи. Не думайте, что другие могут читать ваши мысли.
- Излагайте проблему конкретно и чётко.
Относитесь к своей уязвимости как к силе, и вы удивитесь, увидев, как много людей готовы вам помочь.
Источник: https://betterprogramming.pub/6-factors-that-determine-whether-you-will-succeed-or-fail-ae1dfe446e2b
👍8
День 1824. #ЧтоНовенького
MSTest Runner
Microsoft представили MSTest Runner, небольшую утилиту для запуска тестов под MSTest. Основная цель — повысить переносимость, надёжность и скорость, одновременно предоставляя пользователям расширяемые возможности тестирования.
MSTest Runner представлен как независимый переносимый исполняемый файл с упором на устранение необходимости во внешних инструментах, таких как vstest.console, dotnet test или Visual Studio, для выполнения тестов. Команда разработчиков считает, что он подходит для разработки тестов на устройствах с ограниченной мощностью или объёмом памяти, предлагая упрощённое решение для тестирования.
MSTest Runner поставляется в комплекте с NuGet-пакетом MSTest.TestAdapter, начиная с версии 3.2.0.
По сравнению с VSTest, MSTest Runner предлагает несколько преимуществ:
1) Портативность
Упрощает выполнение тестов, запуская тесты непосредственно из исполняемого файла, устраняя сложности, связанные с традиционной инфраструктурой тестирования. С помощью MSTest Runner проекты рассматриваются как обычные объекты, что позволяет разработчикам использовать существующие инструменты dotnet и запускать тесты на разных компьютерах без дополнительной настройки.
Сообщается, что существует план добиться поддержки NativeAOT. Кроме того, на GitHub представлен пример запуска тестов для приложения dotnet, размещённого в Docker, где нет полноценного .NET SDK.
2) Производительность
MSTest Runner оптимизирует использование ресурсов на серверах сборки, по сравнению с dotnet test. Как заявила команда разработчиков, во внутренних проектах Microsoft, внедривших MSTest Runner, наблюдалась существенная экономия в использовании ЦП и памяти, при этом некоторые проекты завершали тесты в три раза быстрее, используя при этом в четыре раза меньше памяти по сравнению с dotnet test.
Также MSTest Runner вводит новые настройки по умолчанию, отдающие приоритет безопасности и снижающие вероятность случайного пропуска выполнения теста. Кроме того, благодаря своей архитектуре без сканирования папок, динамической загрузки или рефлексии для обнаружения расширений гарантирует согласованное поведение как в локальной среде, так и в среде CI. А асинхронная природа утилиты сводит к минимуму зависания и взаимоблокировки, устраняя распространённые проблемы, наблюдаемые при использовании VSTest.
3) Расширяемость
MSTest Runner предлагает гибкую модель, позволяющую пользователям расширять или переопределять различные аспекты выполнения тестов. Эта модель поддерживает генераторы пользовательских отчётов, оркестрацию тестов, средства ведения журнала и дополнительные параметры командной строки. Microsoft предоставляет список расширений с обещанием постоянно его дополнять.
Хотя в настоящее время утилита поддерживает только MSTest, она была намеренно построена с учётом независимости от платформы. Было принято решение сосредоточиться на MSTest, который обеспечивает большую гибкость, простоту обратной совместимости, а также более быструю и уверенную реализацию изменений благодаря знакомству команды с кодовой базой MSTest. Разработчикам предлагается проголосовать и оставить свои пожелания относительно других платформ тестирования.
Источник: https://www.infoq.com/news/2024/01/introducing-new-ms-test-runner/
MSTest Runner
Microsoft представили MSTest Runner, небольшую утилиту для запуска тестов под MSTest. Основная цель — повысить переносимость, надёжность и скорость, одновременно предоставляя пользователям расширяемые возможности тестирования.
MSTest Runner представлен как независимый переносимый исполняемый файл с упором на устранение необходимости во внешних инструментах, таких как vstest.console, dotnet test или Visual Studio, для выполнения тестов. Команда разработчиков считает, что он подходит для разработки тестов на устройствах с ограниченной мощностью или объёмом памяти, предлагая упрощённое решение для тестирования.
MSTest Runner поставляется в комплекте с NuGet-пакетом MSTest.TestAdapter, начиная с версии 3.2.0.
По сравнению с VSTest, MSTest Runner предлагает несколько преимуществ:
1) Портативность
Упрощает выполнение тестов, запуская тесты непосредственно из исполняемого файла, устраняя сложности, связанные с традиционной инфраструктурой тестирования. С помощью MSTest Runner проекты рассматриваются как обычные объекты, что позволяет разработчикам использовать существующие инструменты dotnet и запускать тесты на разных компьютерах без дополнительной настройки.
Сообщается, что существует план добиться поддержки NativeAOT. Кроме того, на GitHub представлен пример запуска тестов для приложения dotnet, размещённого в Docker, где нет полноценного .NET SDK.
2) Производительность
MSTest Runner оптимизирует использование ресурсов на серверах сборки, по сравнению с dotnet test. Как заявила команда разработчиков, во внутренних проектах Microsoft, внедривших MSTest Runner, наблюдалась существенная экономия в использовании ЦП и памяти, при этом некоторые проекты завершали тесты в три раза быстрее, используя при этом в четыре раза меньше памяти по сравнению с dotnet test.
Также MSTest Runner вводит новые настройки по умолчанию, отдающие приоритет безопасности и снижающие вероятность случайного пропуска выполнения теста. Кроме того, благодаря своей архитектуре без сканирования папок, динамической загрузки или рефлексии для обнаружения расширений гарантирует согласованное поведение как в локальной среде, так и в среде CI. А асинхронная природа утилиты сводит к минимуму зависания и взаимоблокировки, устраняя распространённые проблемы, наблюдаемые при использовании VSTest.
3) Расширяемость
MSTest Runner предлагает гибкую модель, позволяющую пользователям расширять или переопределять различные аспекты выполнения тестов. Эта модель поддерживает генераторы пользовательских отчётов, оркестрацию тестов, средства ведения журнала и дополнительные параметры командной строки. Microsoft предоставляет список расширений с обещанием постоянно его дополнять.
Хотя в настоящее время утилита поддерживает только MSTest, она была намеренно построена с учётом независимости от платформы. Было принято решение сосредоточиться на MSTest, который обеспечивает большую гибкость, простоту обратной совместимости, а также более быструю и уверенную реализацию изменений благодаря знакомству команды с кодовой базой MSTest. Разработчикам предлагается проголосовать и оставить свои пожелания относительно других платформ тестирования.
Источник: https://www.infoq.com/news/2024/01/introducing-new-ms-test-runner/
👍8👎3
День 1825. #ЗаметкиНаПолях
Короткие URL в .NET. Начало
Короткие URL - простой, но мощный инструмент, преобразующий длинные URL в более удобные и короткие. Два популярных инструмента сокращения URL-адресов — Bitly и TinyURL. Посмотрим, как создать его самому.
Нам нужны 2 конечные точки:
- Генерирующая уникальный кода для данного URL,
- Перенаправляющая с короткой ссылки, на исходный URL.
URL будут храниться в БД.
Длина кода и набор символов определяют, сколько коротких URL может сгенерировать система. Для генерации будем использовать Random, т.к. его легко реализовать, и он имеет приемлемо низкий уровень коллизий.
Модель данных
ShortUrl представляет URL, хранящиеся в нашей системе:
Класс включает исходный URL (Url) и уникальный код (Code), представляющий сокращённый URL. Id и CreatedOn используются для БД и отслеживания.
В AppDbContext настроим сущность и контекст БД:
- Максимальную длину кода,
- Уникальный индекс на столбце Code, чтобы в БД не было повторяющихся значений кода.
- Также некоторые БД обрабатывают строки без учета регистра. Это значительно уменьшает количество доступных коротких URL. Нужно настроить БД для обработки уникального кода с учетом регистра:
Генерация уникального кода
Есть несколько алгоритмов реализации. Мы хотим равномерного распределения уникальных кодов по всем возможным значениям. Это поможет уменьшить коллизии. Здесь рассмотрим генератор случайного кода с предопределённым алфавитом. Его просто реализовать, и вероятность коллизий относительно невелика. ShortLinkSettings содержит две константы - длину кода и алфавит:
В алфавите 62 символа, что даёт больше 3х триллионов(!!!) уникальных комбинаций.
UrlShorteningService генерирует уникальные коды. Мы выбираем случайные символы из алфавита до достижения длины, а затем проверяем, нет ли уже такого кода в БД. Если нет, возвращаем его, если есть, повторяем процесс:
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/how-to-build-a-url-shortener-with-dotnet
Короткие URL в .NET. Начало
Короткие URL - простой, но мощный инструмент, преобразующий длинные URL в более удобные и короткие. Два популярных инструмента сокращения URL-адресов — Bitly и TinyURL. Посмотрим, как создать его самому.
Нам нужны 2 конечные точки:
- Генерирующая уникальный кода для данного URL,
- Перенаправляющая с короткой ссылки, на исходный URL.
URL будут храниться в БД.
Длина кода и набор символов определяют, сколько коротких URL может сгенерировать система. Для генерации будем использовать Random, т.к. его легко реализовать, и он имеет приемлемо низкий уровень коллизий.
Модель данных
ShortUrl представляет URL, хранящиеся в нашей системе:
public class ShortUrl
{
public Guid Id { get; set; }
public string Url { get; set; }
public string Code { get; set; }
public DateTime CreatedOn { get; set; }
}
Класс включает исходный URL (Url) и уникальный код (Code), представляющий сокращённый URL. Id и CreatedOn используются для БД и отслеживания.
В AppDbContext настроим сущность и контекст БД:
- Максимальную длину кода,
- Уникальный индекс на столбце Code, чтобы в БД не было повторяющихся значений кода.
- Также некоторые БД обрабатывают строки без учета регистра. Это значительно уменьшает количество доступных коротких URL. Нужно настроить БД для обработки уникального кода с учетом регистра:
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions opts)
: base(options)
{ }
public DbSet<ShortUrl> ShortUrls { get; set; }
protected override void
OnModelCreating(ModelBuilder mb)
{
mb.Entity<ShortUrl>(b =>
{
b.Property(u => u.Code)
.HasMaxLength(ShortLinkSettings.Length);
b.HasIndex(u => u.Code)
.IsUnique();
});
}
}
Генерация уникального кода
Есть несколько алгоритмов реализации. Мы хотим равномерного распределения уникальных кодов по всем возможным значениям. Это поможет уменьшить коллизии. Здесь рассмотрим генератор случайного кода с предопределённым алфавитом. Его просто реализовать, и вероятность коллизий относительно невелика. ShortLinkSettings содержит две константы - длину кода и алфавит:
public static class ShortLinkSettings
{
public const int Length = 7;
public const string Alphabet =
"ABCDEF…xyz01…89";
}
В алфавите 62 символа, что даёт больше 3х триллионов(!!!) уникальных комбинаций.
UrlShorteningService генерирует уникальные коды. Мы выбираем случайные символы из алфавита до достижения длины, а затем проверяем, нет ли уже такого кода в БД. Если нет, возвращаем его, если есть, повторяем процесс:
public class UrlShorteningService(AppDbContext ctx)
{
private Random _rnd = new();
public async Task<string> GetCode()
{
const len = ShortLinkSettings.Length;
var chars = new char[len];
const int maxVal =
ShortLinkSettings.Alphabet.Length;
while (true)
{
for (var i = 0; i < len; i++)
{
var idx = _rnd.Next(maxVal);
chars[i] =
ShortLinkSettings.Alphabet[idx];
}
var code = new string(chars);
if (!await ctx.ShortUrls.AnyAsync(
s => s.Code == code))
return code;
}
}
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/how-to-build-a-url-shortener-with-dotnet
👍16
День 1826. #ЗаметкиНаПолях
Короткие URL в .NET. Окончание
Начало
Теперь создадим конечные точки для минимального API.
Первая принимает URL, создаёт короткий URL и возвращает его:
Здесь возникает небольшая ситуация гонки, поскольку мы сначала генерируем уникальный код, а затем вставляем его в БД. Параллельный запрос может сгенерировать тот же уникальный код и вставить его в БД до того, как мы завершим транзакцию. Однако вероятность того, что это произойдет, невелика, кроме того, уникальный ключ в БД защищает нас от дублирования значений.
Вторая конечная точка перенаправит на исходный URL при доступе к сокращённому:
Эта конечная точка ищет код в БД и, если он найден, перенаправляет пользователя на исходный длинный URL. Ответ будет иметь код состояния 302 (Found) согласно стандартам HTTP.
Недостатки и улучшения
1. Недостатком реализации сервиса является длинная задержка, т.к. мы проверяем каждый генерируемый код в БД. Улучшением может стать заблаговременное создание уникальных кодов в БД.
2. Кэширование второй конечной точки позволит снизить нагрузку на БД для часто используемых коротких URL.
Источник: https://www.milanjovanovic.tech/blog/how-to-build-a-url-shortener-with-dotnet
Короткие URL в .NET. Окончание
Начало
Теперь создадим конечные точки для минимального API.
Первая принимает URL, создаёт короткий URL и возвращает его:
app.MapPost("shorten", async (
string url,
UrlShorteningService svc,
AppDbContext dbCtx,
HttpContext httpCtx) =>
{
if (!Uri.TryCreate(url, UriKind.Absolute, out _))
return Results.BadRequest(
"Предоставленный URL неверный.");
var code = await svc.GetCode();
var req = httpCtx.Request;
var shortUrl = new ShortUrl
{
Id = Guid.NewGuid(),
Url = url,
Code = code,
CreatedOn = DateTime.UtcNow
};
dbCtx.ShortenedUrls.Add(shortUrl);
await dbCtx.SaveChangesAsync();
return Results.Ok(
$"{req.Scheme}://{req.Host}/{code}");
});
Здесь возникает небольшая ситуация гонки, поскольку мы сначала генерируем уникальный код, а затем вставляем его в БД. Параллельный запрос может сгенерировать тот же уникальный код и вставить его в БД до того, как мы завершим транзакцию. Однако вероятность того, что это произойдет, невелика, кроме того, уникальный ключ в БД защищает нас от дублирования значений.
Вторая конечная точка перенаправит на исходный URL при доступе к сокращённому:
csharp
app.MapGet("{code}",
async (
string code,
AppDbContext dbCtx) =>
{
var shortUrl = await
dbCtx.ShortUrls
.SingleOrDefaultAsync(
s => s.Code == code);
if (shortUrl is null)
return Results.NotFound();
return Results.Redirect(shortUrl.Url);
});
Эта конечная точка ищет код в БД и, если он найден, перенаправляет пользователя на исходный длинный URL. Ответ будет иметь код состояния 302 (Found) согласно стандартам HTTP.
Недостатки и улучшения
1. Недостатком реализации сервиса является длинная задержка, т.к. мы проверяем каждый генерируемый код в БД. Улучшением может стать заблаговременное создание уникальных кодов в БД.
2. Кэширование второй конечной точки позволит снизить нагрузку на БД для часто используемых коротких URL.
Источник: https://www.milanjovanovic.tech/blog/how-to-build-a-url-shortener-with-dotnet
👍7
День 1827.
Нам 5 лет!
А вас почти 4000. Спасибо, что читаете, лайкаете и комментируете.
Для тех, кто пришёл недавно, вот здесь подборка тематических тегов. Либо вы просто можете поискать по сообщениям в канале то, что вам нужно.
Также добро пожаловать в наш чат, где собралась неплохая компания, и где вам всегда постараются помочь.
Ещё раз спасибо, что читаете, а те, кто кроме этого хочет поддержать, добро пожаловать в Boosty или Patreon.
Нам 5 лет!
А вас почти 4000. Спасибо, что читаете, лайкаете и комментируете.
Для тех, кто пришёл недавно, вот здесь подборка тематических тегов. Либо вы просто можете поискать по сообщениям в канале то, что вам нужно.
Также добро пожаловать в наш чат, где собралась неплохая компания, и где вам всегда постараются помочь.
Ещё раз спасибо, что читаете, а те, кто кроме этого хочет поддержать, добро пожаловать в Boosty или Patreon.
👍84👎1
.NET Разработчик pinned «День 1827. Нам 5 лет! А вас почти 4000. Спасибо, что читаете, лайкаете и комментируете. Для тех, кто пришёл недавно, вот здесь подборка тематических тегов. Либо вы просто можете поискать по сообщениям в канале то, что вам нужно. Также добро пожаловать в…»
День 1828. #ЧтоНовенького
Новые Функции Расширения Visual Studio GitHub Copilot
В последнем выпуске расширения Visual Studio GitHub Copilot Chat представлены две примечательные функции повышения производительности: команды с косой чертой и контекстные переменные. Кроме того, разработчики могут изучить несколько функций в превью-версии, такие как Помощник по исключениям, Анализ сбоев тестов, Рекомендации для выражений точек останова, Рекомендации по сообщениям коммита и многие другие.
Первым заметным дополнением является добавление команд с косой чертой, представляющих собой набор специализированных директив, которые разработчики могут использовать в интерфейсе чата для запуска определённых действий, связанных с кодом. Введено несколько команд:
-
-
-
-
-
-
-
Другая примечательная новинка - функция контекстных переменных, которая позволяет разработчикам легко включать в вопросы файлы из решения, используя символ
Также доступно несколько экспериментальных функций в превью-версии.
- Ассистент по исключениям в отладчике автоматически добавит ссылку Ask Copilot (Спросить Copilot) в окно сообщения об ошибке при отладке.
- Solution Reference (Справочник решения), позволяющий пользователям находить ссылки на элементы кода в решении и перемещаться по ним. При использовании директивы
- Предложения в профилировщике производительности проанализируют данные о производительности, собранные профилировщиком производительности Visual Studio, и покажут рекомендации по оптимизации скорости кода, использования памяти и скорости ответа.
- Анализ сбоев тестов поможет отлаживать и исправлять сбои модульных тестов. Copilot предоставит вам полезную информацию о сбое теста, такую как сообщение с утверждения, ожидаемые и фактические значения, исходный код и возможные решения.
Отзывы сообщества о Visual Studio Copilot Chat в целом положительные: пользователи хвалят такие функции, как
Некоторые пользователи сравнивают Copilot с другими инструментами, подчёркивая его ценность как встроенного инструмента, но отдавая предпочтение инструментам с расширенными функциями. В целом отзывы сообщества подчеркивают как высокую оценку существующих функций, так и стремление к постоянному совершенствованию инструмента.
Для использования Visual Studio Copilot Chat нужно использовать Visual Studio 2022 версии 17.8 или выше. Кроме того, необходимо убедиться, что учётная запись GitHub, с которой выполнен вход в Visual Studio, связана с активной подпиской GitHub Copilot.
Источник: https://www.infoq.com/news/2024/01/vs-github-copilot-new-features/
Новые Функции Расширения Visual Studio GitHub Copilot
В последнем выпуске расширения Visual Studio GitHub Copilot Chat представлены две примечательные функции повышения производительности: команды с косой чертой и контекстные переменные. Кроме того, разработчики могут изучить несколько функций в превью-версии, такие как Помощник по исключениям, Анализ сбоев тестов, Рекомендации для выражений точек останова, Рекомендации по сообщениям коммита и многие другие.
Первым заметным дополнением является добавление команд с косой чертой, представляющих собой набор специализированных директив, которые разработчики могут использовать в интерфейсе чата для запуска определённых действий, связанных с кодом. Введено несколько команд:
-
/doc
добавит документацию в код.-
/explain
даст подробное объяснение кода, -
/fix
предложит решения выявленных проблем в выбранном коде,-
/generate
запустит Copilot для создания кода по запросу,-
/help
откроет помощь в Copilot Chat,-
/optimize
проанализирует и улучшит время выполнения выбранного кода,-
/tests
создаст модульные тесты для выбранного кода.Другая примечательная новинка - функция контекстных переменных, которая позволяет разработчикам легко включать в вопросы файлы из решения, используя символ
#
. Это позволяет Copilot получать доступ к содержимому файлов, на которые имеются ссылки, и предоставлять более целенаправленные ответы. Например, разработчики могут задать вопрос о функциональности определённого файла, например #Main.cs
, и получить соответствующую информацию в чате Copilot. Обратите внимание, что в один вопрос можно включить несколько файлов. В ответах будут видны ссылки на добавленные файлы. Нажатие на эти ссылки перенаправит пользователей к их содержимому, предлагая удобный способ навигации и понимания файлов, на которые имеются ссылки.Также доступно несколько экспериментальных функций в превью-версии.
- Ассистент по исключениям в отладчике автоматически добавит ссылку Ask Copilot (Спросить Copilot) в окно сообщения об ошибке при отладке.
- Solution Reference (Справочник решения), позволяющий пользователям находить ссылки на элементы кода в решении и перемещаться по ним. При использовании директивы
#solution
, вы дадите Copilot команду добавить код решения в контекст вопроса и предложить более точное решение. - Предложения в профилировщике производительности проанализируют данные о производительности, собранные профилировщиком производительности Visual Studio, и покажут рекомендации по оптимизации скорости кода, использования памяти и скорости ответа.
- Анализ сбоев тестов поможет отлаживать и исправлять сбои модульных тестов. Copilot предоставит вам полезную информацию о сбое теста, такую как сообщение с утверждения, ожидаемые и фактические значения, исходный код и возможные решения.
Отзывы сообщества о Visual Studio Copilot Chat в целом положительные: пользователи хвалят такие функции, как
#solution
. Однако есть и проблемы с некоторыми командами с косой чертой, такими как /doc
для больших блоков кода, а также слишком общий характер описаний в /explain
. Пользователи предлагают варианты настройки, такие как выбор языка для сообщений коммита. Есть также предложения относительно будущих улучшений, таких как возможности мониторинга и выражения эмоций.Некоторые пользователи сравнивают Copilot с другими инструментами, подчёркивая его ценность как встроенного инструмента, но отдавая предпочтение инструментам с расширенными функциями. В целом отзывы сообщества подчеркивают как высокую оценку существующих функций, так и стремление к постоянному совершенствованию инструмента.
Для использования Visual Studio Copilot Chat нужно использовать Visual Studio 2022 версии 17.8 или выше. Кроме того, необходимо убедиться, что учётная запись GitHub, с которой выполнен вход в Visual Studio, связана с активной подпиской GitHub Copilot.
Источник: https://www.infoq.com/news/2024/01/vs-github-copilot-new-features/
👍4👎2
День 1829. #Карьера
Когда Начальник Вас не Слушает
В идеале руководитель должен вдохновлять и поддерживать вас, назначать вам проекты и направлять вас к росту и устранять любые препятствия. Обычно не всё так гладко. Многие сотрудники жалуются, что их менеджеры «просто не слушают»: от явного игнорирования при предоставлении обратной связи до упущения продвижения по службе. Рассмотрим как мы можем каждый раз достигать наилучшего результата в разных сценариях.
1. Начальник не слушает отзывы
Возможно, будет полезно обсудить проблему с остальной командой. Это типично для всех или направлено конкретно против вас? Убедитесь, что ваш руководитель понимает ваши отзывы, сделав их прямыми, конкретными и своевременными. Изучите, как вы выражаете эту обратную связь, поскольку ваши стили общения могут противоречить. Во время встреч обращайте внимание на то, как с ним разговаривают другие люди, и поймите, какой стиль общения привлекает внимание вашего начальника.
2. Начальник игнорирует мои идеи
Упорно работать над чем-то может показаться деморализующим, если начальство игнорирует ваш вклад и выбирает совершенно другое направление.
В таких случаях может помочь переоценка вашей презентации. Постарайтесь найти наиболее важную часть вашей идеи и договориться о ней, вместо того чтобы настаивать на полном пакете.
Сосредоточьтесь на чём-то, что принесет ощутимые результаты для бизнеса либо напрямую (за счет зарабатывания денег), либо косвенно (например, за счет снижения затрат или повышения эффективности). Если возможно, создайте доказательство концепции и измерьте результат. Представьте эти результаты руководителю.
3. Начальник не помогает с проблемами по работе
Всего 23% сотрудников сообщают, что их руководитель всегда конструктивно реагирует, когда они делятся своими рабочими проблемами, а 17% утверждают, что их руководитель вообще им не помогает.
Постарайтесь разобраться в проблеме. Может у него много дел, и нет времени вам помочь. Тогда предложите свою помощь в каких-то вопросах.
Ещё одна причина, может быть в том, что начальник хочет, чтобы вы сами нашли решение и получили опыт. Если вы исчерпали все возможные варианты и не знаете, как двигаться дальше, важно подчеркнуть это.
4. Начальник игнорирует мой запрос на повышение
Во-первых, вы просили или просто намекнули об этом? Если явно просили, попробуйте узнать, это осознанное и окончательное решение, проблема с бюджетом или местом в текущей команде? Если не хватает бюджета, спросите, есть ли график продвижений и что нужно сделать, чтобы получить повышение, и когда на него рассчитывать?
Поднимите проблему
Не уклоняйтесь от обсуждения проблем и не позволяйте проблеме накапливаться. Относитесь к этому так же, как к любой обратной связи; давайте её своевременно и привяжите к конкретным фактам. Какое именно поведение начальства заставило вас почувствовать, что вас игнорируют? Соблазнительно начать жаловаться, но полезнее переключиться в режим решения проблем. Подумайте, как вы можете быть наиболее полезны для бизнеса.
Говорить ли с начальством начальства?
Иногда может возникнуть соблазн переступить через голову. Прежде чем делать это, учтите последствия. Это необратимо повлияет на ваши отношения. Даже если вы добьётесь своего, после этого вашему руководителю будет трудно вам доверять. В некоторых компаниях начальник вашего руководителя наотрез откажется с вами разговаривать, вам могут сделать выговор или даже уволить. Это можно делать, только если произойдёт что-то неэтичное или незаконное.
Итого
Вы не можете «исправить» людей. Ожидать, что другие будут соответствовать вашему представлению о «хорошем поведении», бессмысленно. Для достижения карьерных целей нужно поддерживать продуктивные отношения со своим руководителем. Однако не следует перенапрягаться, если видите, что это не работает. Вместо этого сосредоточьтесь на своей цели, продуктивности и вкладе в организацию и подумайте о том, чтобы подать заявку на работу в другой команде.
Источник: https://betterprogramming.pub/when-your-manager-does-not-listen-55875a35c974
Когда Начальник Вас не Слушает
В идеале руководитель должен вдохновлять и поддерживать вас, назначать вам проекты и направлять вас к росту и устранять любые препятствия. Обычно не всё так гладко. Многие сотрудники жалуются, что их менеджеры «просто не слушают»: от явного игнорирования при предоставлении обратной связи до упущения продвижения по службе. Рассмотрим как мы можем каждый раз достигать наилучшего результата в разных сценариях.
1. Начальник не слушает отзывы
Возможно, будет полезно обсудить проблему с остальной командой. Это типично для всех или направлено конкретно против вас? Убедитесь, что ваш руководитель понимает ваши отзывы, сделав их прямыми, конкретными и своевременными. Изучите, как вы выражаете эту обратную связь, поскольку ваши стили общения могут противоречить. Во время встреч обращайте внимание на то, как с ним разговаривают другие люди, и поймите, какой стиль общения привлекает внимание вашего начальника.
2. Начальник игнорирует мои идеи
Упорно работать над чем-то может показаться деморализующим, если начальство игнорирует ваш вклад и выбирает совершенно другое направление.
В таких случаях может помочь переоценка вашей презентации. Постарайтесь найти наиболее важную часть вашей идеи и договориться о ней, вместо того чтобы настаивать на полном пакете.
Сосредоточьтесь на чём-то, что принесет ощутимые результаты для бизнеса либо напрямую (за счет зарабатывания денег), либо косвенно (например, за счет снижения затрат или повышения эффективности). Если возможно, создайте доказательство концепции и измерьте результат. Представьте эти результаты руководителю.
3. Начальник не помогает с проблемами по работе
Всего 23% сотрудников сообщают, что их руководитель всегда конструктивно реагирует, когда они делятся своими рабочими проблемами, а 17% утверждают, что их руководитель вообще им не помогает.
Постарайтесь разобраться в проблеме. Может у него много дел, и нет времени вам помочь. Тогда предложите свою помощь в каких-то вопросах.
Ещё одна причина, может быть в том, что начальник хочет, чтобы вы сами нашли решение и получили опыт. Если вы исчерпали все возможные варианты и не знаете, как двигаться дальше, важно подчеркнуть это.
4. Начальник игнорирует мой запрос на повышение
Во-первых, вы просили или просто намекнули об этом? Если явно просили, попробуйте узнать, это осознанное и окончательное решение, проблема с бюджетом или местом в текущей команде? Если не хватает бюджета, спросите, есть ли график продвижений и что нужно сделать, чтобы получить повышение, и когда на него рассчитывать?
Поднимите проблему
Не уклоняйтесь от обсуждения проблем и не позволяйте проблеме накапливаться. Относитесь к этому так же, как к любой обратной связи; давайте её своевременно и привяжите к конкретным фактам. Какое именно поведение начальства заставило вас почувствовать, что вас игнорируют? Соблазнительно начать жаловаться, но полезнее переключиться в режим решения проблем. Подумайте, как вы можете быть наиболее полезны для бизнеса.
Говорить ли с начальством начальства?
Иногда может возникнуть соблазн переступить через голову. Прежде чем делать это, учтите последствия. Это необратимо повлияет на ваши отношения. Даже если вы добьётесь своего, после этого вашему руководителю будет трудно вам доверять. В некоторых компаниях начальник вашего руководителя наотрез откажется с вами разговаривать, вам могут сделать выговор или даже уволить. Это можно делать, только если произойдёт что-то неэтичное или незаконное.
Итого
Вы не можете «исправить» людей. Ожидать, что другие будут соответствовать вашему представлению о «хорошем поведении», бессмысленно. Для достижения карьерных целей нужно поддерживать продуктивные отношения со своим руководителем. Однако не следует перенапрягаться, если видите, что это не работает. Вместо этого сосредоточьтесь на своей цели, продуктивности и вкладе в организацию и подумайте о том, чтобы подать заявку на работу в другой команде.
Источник: https://betterprogramming.pub/when-your-manager-does-not-listen-55875a35c974
👍10👎2
День 1830. #ЗаметкиНаПолях
Проверяем, Пустая ли Коллекция в C#
В C# существуют разные способы проверить, пустая ли коллекция. В зависимости от типа коллекции вы можете проверить свойства Length, Count или IsEmpty. Также можно использовать метод расширения Enumerable.Any().
В C# 11, вы можете использовать сопоставление с образцом, чтобы позволить компилятору использовать лучший метод для проверки того, пуста ли коллекция. Не нужно запоминать правильное имя свойства, можно использовать оператор is:
Обратите внимание, что предыдущий код не совсем эквивалентен проверке свойства Length. Если экземпляру коллекции присвоить NULL, проверка свойства вызывает исключение NullReferenceException, а сопоставление с образцом вернёт false:
Проверить на null и пустую коллекцию, можно так:
Ту же логику можно использовать и для строк, хотя использование string.IsNullOrEmpty гораздо более распространено:
Источник: https://www.meziantou.net/checking-if-a-collection-is-empty-in-csharp.htm
Проверяем, Пустая ли Коллекция в C#
В C# существуют разные способы проверить, пустая ли коллекция. В зависимости от типа коллекции вы можете проверить свойства Length, Count или IsEmpty. Также можно использовать метод расширения Enumerable.Any().
// массив: Length
int[] array = ...;
var isEmpty = array.Length == 0;
// List: Count
List<int> list = ...;
var isEmpty = list.Count == 0;
// ImmutableArray<T>: IsEmpty
ImmutableArray<int> immArray = ...;
var isEmpty = immArray.IsEmpty;
// Span: IsEmpty
Span<int> span = ...;
var isEmpty = span.IsEmpty;
// метод расширения
List<int> list = ...;
var isEmpty = !list.Any();
В C# 11, вы можете использовать сопоставление с образцом, чтобы позволить компилятору использовать лучший метод для проверки того, пуста ли коллекция. Не нужно запоминать правильное имя свойства, можно использовать оператор is:
var collection = ...;
var isEmpty = collection is [];
Обратите внимание, что предыдущий код не совсем эквивалентен проверке свойства Length. Если экземпляру коллекции присвоить NULL, проверка свойства вызывает исключение NullReferenceException, а сопоставление с образцом вернёт false:
int[] array = null;
// NullReferenceException
var isEmpty = array.Length == 0;
// false
var isEmpty = array is [];
Проверить на null и пустую коллекцию, можно так:
var isNullOrEmpty = array is null or [];
Ту же логику можно использовать и для строк, хотя использование string.IsNullOrEmpty гораздо более распространено:
string str = "";
isEmpty = str is "";
isEmpty = str is [];
Источник: https://www.meziantou.net/checking-if-a-collection-is-empty-in-csharp.htm
👍37
День 1831. #ЧтоНовенького #CSharp13
Три новых метода LINQ в .NET 9
Продолжаем заглядывать в будущее .NET. Сегодня посмотрим, какие новые методы будут добавлены во всеми любимый LINQ.
CountBy
Многие функции LINQ имеют расширение By, в котором можно предоставить функцию выбора для группировки элементов. Например, MinBy, MaxBy, DistinctBy и т. д. Теперь у нас есть новый: CountBy. Он группирует элементы по функции селектора и возвращает перечисление KeyValuePairs. Ключ — это объект, а значение — количество элементов в группе.
Index
Не то, чтоб совсем новинка, это можно делать и сейчас, но с другим синтаксисом. Index возвращает элемент и его индекс в коллекции:
Сейчас такого можно добиться, используя перегрузку метода Select:
Интересно, что в методе Index решили поменять порядок индекса и элемента. Оказывается, это было осознанным решением команды дотнет: «Мы решили сначала возвращать индекс, а затем значение, потому что это кажется более естественным, несмотря на то, что существующий метод Select() сначала возвращает значение, а потом индекс.»
AggregateBy
Этот метод похож на CountBy, но вместо подсчёта элементов он их агрегирует. Вы можете предоставить начальное значение и функцию агрегирования. Функция получает текущее агрегированное значение и текущий элемент в качестве параметров и должна вернуть новое агрегированное значение.
Источник: https://steven-giesel.com/blogPost/0594ba85-356b-47f1-89a9-70e9761c582e/three-new-linq-methods-in-net-9
Три новых метода LINQ в .NET 9
Продолжаем заглядывать в будущее .NET. Сегодня посмотрим, какие новые методы будут добавлены во всеми любимый LINQ.
CountBy
Многие функции LINQ имеют расширение By, в котором можно предоставить функцию выбора для группировки элементов. Например, MinBy, MaxBy, DistinctBy и т. д. Теперь у нас есть новый: CountBy. Он группирует элементы по функции селектора и возвращает перечисление KeyValuePairs. Ключ — это объект, а значение — количество элементов в группе.
public record Person(string FirstName, string LastName);
List<Person> people =
[
new("Steve", "Jobs"),
new("Steve", "Carell"),
new("Elon", "Musk")
];
foreach (var p in people.CountBy(p => p.FirstName))
Console.WriteLine($"{p.Value} людей с именем {p.Key}");
Вывод:
2 людей с именем Steve
1 людей с именем Elon
Index
Не то, чтоб совсем новинка, это можно делать и сейчас, но с другим синтаксисом. Index возвращает элемент и его индекс в коллекции:
foreach (var (index, item) in people.Index())
Console.WriteLine($"№{index}: {item}");
Сейчас такого можно добиться, используя перегрузку метода Select:
foreach (var (item, index) in
people.Select((item, index) => (item, index)))
{
Console.WriteLine($"№{index}: {item}");
}
Интересно, что в методе Index решили поменять порядок индекса и элемента. Оказывается, это было осознанным решением команды дотнет: «Мы решили сначала возвращать индекс, а затем значение, потому что это кажется более естественным, несмотря на то, что существующий метод Select() сначала возвращает значение, а потом индекс.»
AggregateBy
Этот метод похож на CountBy, но вместо подсчёта элементов он их агрегирует. Вы можете предоставить начальное значение и функцию агрегирования. Функция получает текущее агрегированное значение и текущий элемент в качестве параметров и должна вернуть новое агрегированное значение.
public record Person(
string FirstName,
string Department,
int Salary);
List<Person> people =
[
new("Jobs", "Sales", 100),
new("Carell", "Sales", 120),
new("Musk", "IT", 290)
];
var aggregateBy = people.AggregateBy(
p => p.Department,
x => 0,
(x, y) => x + y.Salary
);
foreach (var kvp in aggregateBy)
Console.WriteLine($"ФОТ отдела {kvp.Key}: {kvp.Value}");
Вывод:
ФОТ отдела Sales: 220
ФОТ отдела IT: 290
Источник: https://steven-giesel.com/blogPost/0594ba85-356b-47f1-89a9-70e9761c582e/three-new-linq-methods-in-net-9
👍25
День 1832. #ЗаметкиНаПолях
.http-Файл в Visual Studio не Отправляет Заголовок Авторизации
При отправке запросов к API в Visual Studio возникает странная проблема. Bearer-токен, который в Swagger работает нормально, в файле .http просто игнорируется, что приводит к ошибке 401 Unauthorized.
Проблема
Простой проект Webapi ASP.NET Core, используя шаблон по умолчанию со встроенной поддержкой .http-файлов для выполнения запросов к проекту. Регистрация и вход в систему работают нормально, но попытка доступа к конечной точке, требующей аутентификации, всегда приводит к ошибке 401. Тот же токен, добавленный в тот же заголовок авторизации, отлично работает при использовании Swagger/Swashbuckle в браузере.
Диагностика проблемы
На вкладке Request info (Информация о запросе) в файле .http даже не отображался заголовок Authorization (но отображался кастомный заголовок Authorization2, который был идентичен во всех отношениях, кроме имени). Стало ясно, что это было так и задумано. Проблема в том, что запрос из .http-файла первоначально отправлялся на https://localhost:5206/cart, который перенаправлялся на https://localhost:7248/cart из-за использования промежуточного ПО UseHttpsRedirection.
Конечная точка http была настроена как переменная в верхней части файла .http, поэтому даже в самом файле не было очевидно, что данный запрос использует не тот URL/порт:
На вкладке Request (Запрос) вывода .http-файла отображался URL https://localhost:7248/cart, что никак не обозначает, что он неправильный (не тот, куда шёл изначальный запрос). Единственная проблема – отсутствие заголовка авторизации.
Возможно, было бы неплохо включить на вкладке Request (или где-то еще) информацию о том, что было выполнено перенаправление и что конечный URL не соответствует исходному запрошенному URL.
Заголовки перенаправления и авторизация
Основная проблема тут в том, как работает UseHttpsRedirection. Он отправляет клиенту в ответ заголовок перенаправления, и если клиент настроен на автоматическое следование перенаправлениям, он «молча» переходит на предложенный в перенаправлении URL. Однако также существует соглашение не пересылать заголовки авторизации при перенаправлениях:
«Заголовок Authorization очищается при автоматическом перенаправлении, и обработчик автоматически пытается повторно пройти аутентификацию на целевом URL. Никакие другие заголовки не очищаются. На практике это означает, что приложение не может помещать пользовательскую информацию аутентификации в заголовок Authorization, если есть возможность столкнуться с перенаправлением. Вместо этого приложение должно реализовать и зарегистрировать собственный модуль аутентификации.»
Обратите внимание, что в этом документе буквально говорится, что вам не следует использовать заголовки аутентификации, «если возможно столкнуться с перенаправлением», что, по сути, означает, что вы никогда не должны комбинировать UseHttpsRedirection с API, защищённым токеном.
Посмотрите предложение об изменении поведения файлов .http в Visual Studio и проголосуйте, если заинтересует.
Итого
Надеюсь, изложенное выше поможет сэкономить кому-то время. Если вы получаете ошибку 401 Unauthorized, даже если вы правильно настроили заголовок авторизации, и заметили, что заголовок авторизации отсутствует, ищите виновника в перенаправлении. Это может быть неочевидно в ваших инструментах, особенно если всё настроено на автоматическое следование перенаправлениям.
Источник: https://ardalis.com/http-file-not-sending-auth-header/
.http-Файл в Visual Studio не Отправляет Заголовок Авторизации
При отправке запросов к API в Visual Studio возникает странная проблема. Bearer-токен, который в Swagger работает нормально, в файле .http просто игнорируется, что приводит к ошибке 401 Unauthorized.
Проблема
Простой проект Webapi ASP.NET Core, используя шаблон по умолчанию со встроенной поддержкой .http-файлов для выполнения запросов к проекту. Регистрация и вход в систему работают нормально, но попытка доступа к конечной точке, требующей аутентификации, всегда приводит к ошибке 401. Тот же токен, добавленный в тот же заголовок авторизации, отлично работает при использовании Swagger/Swashbuckle в браузере.
Диагностика проблемы
На вкладке Request info (Информация о запросе) в файле .http даже не отображался заголовок Authorization (но отображался кастомный заголовок Authorization2, который был идентичен во всех отношениях, кроме имени). Стало ясно, что это было так и задумано. Проблема в том, что запрос из .http-файла первоначально отправлялся на https://localhost:5206/cart, который перенаправлялся на https://localhost:7248/cart из-за использования промежуточного ПО UseHttpsRedirection.
Конечная точка http была настроена как переменная в верхней части файла .http, поэтому даже в самом файле не было очевидно, что данный запрос использует не тот URL/порт:
POST {{BaseUrl}}/cart
На вкладке Request (Запрос) вывода .http-файла отображался URL https://localhost:7248/cart, что никак не обозначает, что он неправильный (не тот, куда шёл изначальный запрос). Единственная проблема – отсутствие заголовка авторизации.
Возможно, было бы неплохо включить на вкладке Request (или где-то еще) информацию о том, что было выполнено перенаправление и что конечный URL не соответствует исходному запрошенному URL.
Заголовки перенаправления и авторизация
Основная проблема тут в том, как работает UseHttpsRedirection. Он отправляет клиенту в ответ заголовок перенаправления, и если клиент настроен на автоматическое следование перенаправлениям, он «молча» переходит на предложенный в перенаправлении URL. Однако также существует соглашение не пересылать заголовки авторизации при перенаправлениях:
«Заголовок Authorization очищается при автоматическом перенаправлении, и обработчик автоматически пытается повторно пройти аутентификацию на целевом URL. Никакие другие заголовки не очищаются. На практике это означает, что приложение не может помещать пользовательскую информацию аутентификации в заголовок Authorization, если есть возможность столкнуться с перенаправлением. Вместо этого приложение должно реализовать и зарегистрировать собственный модуль аутентификации.»
Обратите внимание, что в этом документе буквально говорится, что вам не следует использовать заголовки аутентификации, «если возможно столкнуться с перенаправлением», что, по сути, означает, что вы никогда не должны комбинировать UseHttpsRedirection с API, защищённым токеном.
Посмотрите предложение об изменении поведения файлов .http в Visual Studio и проголосуйте, если заинтересует.
Итого
Надеюсь, изложенное выше поможет сэкономить кому-то время. Если вы получаете ошибку 401 Unauthorized, даже если вы правильно настроили заголовок авторизации, и заметили, что заголовок авторизации отсутствует, ищите виновника в перенаправлении. Это может быть неочевидно в ваших инструментах, особенно если всё настроено на автоматическое следование перенаправлениям.
Источник: https://ardalis.com/http-file-not-sending-auth-header/
👍17
День 1833. #ЗаметкиНаПолях
Обзор Инструментов Покрытия Кода для C#. Начало
В этой серии постов рассмотрим различные инструменты покрытия кода в .NET и перечислим их функции.
Но сначала небольшое предупреждение. Если вы ищете способ позволить руководству отслеживать прогресс покрытия кода командой, остановитесь и пересмотрите свои действия. Покрытие кода не должно быть заботой руководства. Это инструмент, который должны использовать разработчики, а не показатель их работы.
Что это и зачем?
Если коротко, измерения покрытия кода показывают, какие строки кода ваш набор тестов выполняет, а какие нет. Простой пример:
Допустим, это единственный метод в нашей кодовой базе, и мы написали один модульный тест, что
Разработчики могут использовать анализ покрытия кода, чтобы увидеть дыры в своём тестировании. В примере выше анализ покрытия кода подскажет, что надо протестировать случай, когда
Инструменты
Практически в любом языке и технологическом стеке есть способы определить, насколько полно набор модульных тестов покрывает вашу кодовую базу. Однако не путайте покрытие кода с оценкой качества ваших тестов. Это просто мера объёма кода, проверяемого тестами. Следующие инструменты помогут вам оценить покрытие кода тестами в .NET.
1. Visual Studio Code Coverage
Если у вас корпоративная версия Visual Studio, вы можете воспользоваться этой возможностью «из коробки». Более подробно об этом можно прочитать на сайте документации Microsoft. Но это хороший, комплексный вариант, который требует совсем немного дополнительной работы, при условии, что у вас есть правильная версия. И у него есть интересные функции:
- Сообщает процент покрытия с различной степенью детализации (например, сборка, класс и т. д.).
- Вы можете выбрать все тесты или их подмножество.
- Подсветка кода в IDE, т.е. он показывает, какие строки кода покрыты тестами, когда вы смотрите на код.
- Продукт Microsoft, поэтому вы можете рассчитывать на обновления и поддержку.
2. dotCover в Rider и ReSharper
Если у вас есть лицензия Visual Studio Enterprise, ваша жизнь во многих отношениях хороша. Если нет, выкладывать $3000 в год только ради покрытия кода, наверное, перебор.
Другой вариант - JetBrains dotCover, который входит в предложения Jetbrains (от $349 до $779 в год). Вы получите анализ покрытия, а также Rider и ReSharper, которые являются действительно классными инструментами.
Некоторые основные функции dotCover:
- Подробная отчётность.
- Исполнители тестов. Тесты также можно запускать с помощью профилировщика dotTrace для измерения производительности.
- Интеграция измерений покрытия как в Visual Studio, так и в CI.
- Переход к покрывающим тестам.
- Хороший обзор «горячих точек», показывающий рискованные методы.
- Отрисовка зеленых/красных операторов в IDE.
Окончание следует…
Источник: https://blog.ndepend.com/guide-code-coverage-tools/
Обзор Инструментов Покрытия Кода для C#. Начало
В этой серии постов рассмотрим различные инструменты покрытия кода в .NET и перечислим их функции.
Но сначала небольшое предупреждение. Если вы ищете способ позволить руководству отслеживать прогресс покрытия кода командой, остановитесь и пересмотрите свои действия. Покрытие кода не должно быть заботой руководства. Это инструмент, который должны использовать разработчики, а не показатель их работы.
Что это и зачем?
Если коротко, измерения покрытия кода показывают, какие строки кода ваш набор тестов выполняет, а какие нет. Простой пример:
public int Divide(int x, int y)
{
if(y != 0)
return x / y;
return 0;
}
Допустим, это единственный метод в нашей кодовой базе, и мы написали один модульный тест, что
Divide(2, 1)
должно вернуть 2
. Мы получим 67% покрытия кода, т.к. тест заставит среду проверить условие, и вернуть x/y, таким образом выполнив 2 строки метода из 3х.Разработчики могут использовать анализ покрытия кода, чтобы увидеть дыры в своём тестировании. В примере выше анализ покрытия кода подскажет, что надо протестировать случай, когда
y=0
.Инструменты
Практически в любом языке и технологическом стеке есть способы определить, насколько полно набор модульных тестов покрывает вашу кодовую базу. Однако не путайте покрытие кода с оценкой качества ваших тестов. Это просто мера объёма кода, проверяемого тестами. Следующие инструменты помогут вам оценить покрытие кода тестами в .NET.
1. Visual Studio Code Coverage
Если у вас корпоративная версия Visual Studio, вы можете воспользоваться этой возможностью «из коробки». Более подробно об этом можно прочитать на сайте документации Microsoft. Но это хороший, комплексный вариант, который требует совсем немного дополнительной работы, при условии, что у вас есть правильная версия. И у него есть интересные функции:
- Сообщает процент покрытия с различной степенью детализации (например, сборка, класс и т. д.).
- Вы можете выбрать все тесты или их подмножество.
- Подсветка кода в IDE, т.е. он показывает, какие строки кода покрыты тестами, когда вы смотрите на код.
- Продукт Microsoft, поэтому вы можете рассчитывать на обновления и поддержку.
2. dotCover в Rider и ReSharper
Если у вас есть лицензия Visual Studio Enterprise, ваша жизнь во многих отношениях хороша. Если нет, выкладывать $3000 в год только ради покрытия кода, наверное, перебор.
Другой вариант - JetBrains dotCover, который входит в предложения Jetbrains (от $349 до $779 в год). Вы получите анализ покрытия, а также Rider и ReSharper, которые являются действительно классными инструментами.
Некоторые основные функции dotCover:
- Подробная отчётность.
- Исполнители тестов. Тесты также можно запускать с помощью профилировщика dotTrace для измерения производительности.
- Интеграция измерений покрытия как в Visual Studio, так и в CI.
- Переход к покрывающим тестам.
- Хороший обзор «горячих точек», показывающий рискованные методы.
- Отрисовка зеленых/красных операторов в IDE.
Окончание следует…
Источник: https://blog.ndepend.com/guide-code-coverage-tools/
👍1
День 1834. #ЗаметкиНаПолях
Обзор Инструментов Покрытия Кода для C#. Окончание
Начало
3. NCrunch
Предоставит вам данные о покрытии кода, а также подсветит покрытый и непокрытый тестами код в IDE. Кроме этого, NCrunch постоянно запускает ваши тесты в режиме реального времени по мере того, как вы печатаете. Это живое модульное тестирование. С NCrunch вам не нужно запускать тесты или даже компилировать код, чтобы получить информацию о том, нарушают ли что-нибудь ваши изменения в коде. Отметки о покрытии будут меняться по мере ввода.
Другие особенности:
- Небольшой и настраиваемый объем используемой памяти.
- Встроенные сведения об исключениях и простая отладка, интегрированная в VS.
- Безопасное многопроцессное параллельное выполнение тестов с возможностью масштабирования.
- Пассивный сбор данных как о покрытии кода, так и о производительности.
- Интеллектуальное выполнение, способное исполнять только те тесты, на которые влияют изменения.
- Очень быстрое выполнение тестов и возможность работать с очень большими наборами тестов.
Цены на NCrunch очень разумные: от $159 до $289 за лицензию для отдельного разработчика.
4. AltCover (ранее известный как OpenCover)
Вот уже несколько лет бесплатный инструмент с открытым кодом AltCover, разработанный на F# Стивом Гилхэмом, заменил известный инструмент OpenCover.
Особенности:
- Инструмент командной строки, предназначенный для сбора информации о покрытии кода .NET. Поддерживаются среды выполнения .NET Core, .NET Framework и Mono.
- Легко интегрируется с задачами MSBuild, предлагая надёжную поддержку для управления инструментом, включая полную интеграцию с функциями dotnet test.
- Предоставляет универсальный расширяемый API, который легко интегрируется с популярными инструментами автоматизации сборки, такими как Fake и Cake.
- Расширяет совместимость со средами PowerShell, предлагая специальный модуль, совместимый как с PowerShell 5.1, так и с PowerShell Core 6+.
- Включает специализированный инструмент визуализации покрытия, основанный на AvaloniaUI.
5. Coverlet
Coverlet — фреймворк покрытия кода, разработанный для .NET и предлагающий поддержку покрытия строк, ветвей и методов. Он совместим с .NET Framework и .NET Core на всех поддерживаемых платформах.
Особенности:
- Легкая интеграция в проекты .NET, не создавая при этом большой нагрузки на систему.
- Бесплатный и с открытым исходным кодом.
- Гибкая конфигурация в соответствии с конкретными требованиями и предпочтениями по покрытию кода.
- Предоставляет надёжную и подробную информацию о коде, помогая выявить области, требующие тестирования и улучшения.
Если вы используете Visual Studio Code, Coverlet станет отличным инструментом.
6. Fine Code Coverage
Бесплатное расширение Visual Studio, предназначенное для предоставления данных о покрытии в IDE. Оно работает со всеми выпусками Visual Studio, включая версию Community. Fine Code Coverage добавляет специальное окно в VS, в котором есть вкладки, предоставляющие ценную информацию о степени покрытия кода с разбитием на проекты и классы, а также подсветку покрытых строк кода.
Источник: https://blog.ndepend.com/guide-code-coverage-tools/
Обзор Инструментов Покрытия Кода для C#. Окончание
Начало
3. NCrunch
Предоставит вам данные о покрытии кода, а также подсветит покрытый и непокрытый тестами код в IDE. Кроме этого, NCrunch постоянно запускает ваши тесты в режиме реального времени по мере того, как вы печатаете. Это живое модульное тестирование. С NCrunch вам не нужно запускать тесты или даже компилировать код, чтобы получить информацию о том, нарушают ли что-нибудь ваши изменения в коде. Отметки о покрытии будут меняться по мере ввода.
Другие особенности:
- Небольшой и настраиваемый объем используемой памяти.
- Встроенные сведения об исключениях и простая отладка, интегрированная в VS.
- Безопасное многопроцессное параллельное выполнение тестов с возможностью масштабирования.
- Пассивный сбор данных как о покрытии кода, так и о производительности.
- Интеллектуальное выполнение, способное исполнять только те тесты, на которые влияют изменения.
- Очень быстрое выполнение тестов и возможность работать с очень большими наборами тестов.
Цены на NCrunch очень разумные: от $159 до $289 за лицензию для отдельного разработчика.
4. AltCover (ранее известный как OpenCover)
Вот уже несколько лет бесплатный инструмент с открытым кодом AltCover, разработанный на F# Стивом Гилхэмом, заменил известный инструмент OpenCover.
Особенности:
- Инструмент командной строки, предназначенный для сбора информации о покрытии кода .NET. Поддерживаются среды выполнения .NET Core, .NET Framework и Mono.
- Легко интегрируется с задачами MSBuild, предлагая надёжную поддержку для управления инструментом, включая полную интеграцию с функциями dotnet test.
- Предоставляет универсальный расширяемый API, который легко интегрируется с популярными инструментами автоматизации сборки, такими как Fake и Cake.
- Расширяет совместимость со средами PowerShell, предлагая специальный модуль, совместимый как с PowerShell 5.1, так и с PowerShell Core 6+.
- Включает специализированный инструмент визуализации покрытия, основанный на AvaloniaUI.
5. Coverlet
Coverlet — фреймворк покрытия кода, разработанный для .NET и предлагающий поддержку покрытия строк, ветвей и методов. Он совместим с .NET Framework и .NET Core на всех поддерживаемых платформах.
Особенности:
- Легкая интеграция в проекты .NET, не создавая при этом большой нагрузки на систему.
- Бесплатный и с открытым исходным кодом.
- Гибкая конфигурация в соответствии с конкретными требованиями и предпочтениями по покрытию кода.
- Предоставляет надёжную и подробную информацию о коде, помогая выявить области, требующие тестирования и улучшения.
Если вы используете Visual Studio Code, Coverlet станет отличным инструментом.
6. Fine Code Coverage
Бесплатное расширение Visual Studio, предназначенное для предоставления данных о покрытии в IDE. Оно работает со всеми выпусками Visual Studio, включая версию Community. Fine Code Coverage добавляет специальное окно в VS, в котором есть вкладки, предоставляющие ценную информацию о степени покрытия кода с разбитием на проекты и классы, а также подсветку покрытых строк кода.
Источник: https://blog.ndepend.com/guide-code-coverage-tools/
👍12👎1
День 1835. #ЗаметкиНаПолях
Пять Шагов по Управлению Легаси-Кодом. Начало
Работать с легаси-кодом не особо весело, но это неизбежно. Разработчик вы, технический руководитель или менеджер продукта, наступит момент, когда какая-то работа, которую вы хотите выполнить, будет связана с устаревшим кодом. Рассмотрим, что на самом деле означает устаревший код и как продумать возможные решения для улучшения состояния кодовой базы и способностей вашей команды эффективно поставлять функции.
1. Принятие существования легаси-кода
Прежде чем приступить к работе с устаревшим кодом, признать, что все кодовые базы и все команды будут иметь код, который они определяют как «устаревший». И это не вина ни команды, ни конкретного разработчика. Существуют методы поддержки низкого уровня легаси-кода и активного его сокращения, но искоренить весь устаревший код — это неправильная, нереалистичная цель, которая, вероятно, контрпродуктивна для бизнеса и его потребностей.
2. Реалистичный подход к определению легаси-кода
Термин «устаревший код» часто используется, и для команды важно иметь чёткое определение, которое разделяет и понимает каждый. Старый код не обязательно является легаси-кодом. Понятие легаси-кода связано не столько с его возрастом, сколько с характеристиками, которые делают работу над ним сложной и непродуктивной, например:
- Отсутствие автоматизированных тестов. Когда разработчики вносят изменения в этот код, им приходится тестировать его вручную, поскольку не существует автоматического покрытия ни на каком уровне (модульные тесты, интеграционные тесты, сквозные тесты и т. д.).
- Отсутствие документации. Когда разработчикам приходится работать с этим кодом, им сложно его понять. Это может быть связано с тем, что код написан так, что его функциональность становится нечёткой, но на это также влияет отсутствие документации. Это может быть не буквальная документация, а просто контекст того, как он появился: проектный документ с чёткой мотивацией, почему эта функция существует, и стратегией того, как она будет реализована.
- Отсутствие эксперта. Когда команда вносит изменения в код, есть ли человек, который сможет его проверить? Это часто можно заметить по обзорам кода, которые выглядят как быстрое «вроде правильно», потому что рецензенту не хватает контекста и знаний для проведения тщательного анализа. Наиболее вероятный сценарий: рассматриваемый код был написан кем-то, кто покинул команду, и никто больше не работал над этой частью кодовой базы.
Важно чётко понимать, почему с кодом сложно работать и что с этим можно сделать. Просто старый код, но с документацией и тестами, не является устаревшим кодом. Даже код, не имеющий тестов, но с хорошей документацией и известный команде, не обязательно легаси. Ситуацию можно улучшить, просто потратив время на добавление тестов. Тогда у нас будет просто старый, а не легаси-код.
3. Приоритет обновления легаси-кода
Как только код будет обоснованно признан «устаревшим», важно подумать о ценности, которую команда может получить, переписав или обновив код. Может возникнуть соблазн думать об обновлении всего легаси-кода, но это ошибочно. Допустим, есть два блока легаси-кода. Каким заняться в первую очередь?
Определите как часто блок кода должен меняться. Если один блок связан с критически важной функцией, то устаревший статус кода будет иметь огромное влияние, замедляя работу инженеров, снижая удовлетворённость и задерживая релизы.
С другой стороны, если устаревший код находится в блоке, к которому редко прикасаются, не имеет запланированных функций, которые вынудили бы его менять, и всё работает, не создавая проблем для пользователей, какой смысл в переписывании кода?
Планируя инвестиции в устаревший код, сосредотачивайтесь не на технических преимуществах переписывания, а на том, что переписывание даст бизнесу в целом.
Окончание следует…
Источник: https://leaddev.com/legacy-technical-debt-migrations/five-steps-managing-legacy-code
Пять Шагов по Управлению Легаси-Кодом. Начало
Работать с легаси-кодом не особо весело, но это неизбежно. Разработчик вы, технический руководитель или менеджер продукта, наступит момент, когда какая-то работа, которую вы хотите выполнить, будет связана с устаревшим кодом. Рассмотрим, что на самом деле означает устаревший код и как продумать возможные решения для улучшения состояния кодовой базы и способностей вашей команды эффективно поставлять функции.
1. Принятие существования легаси-кода
Прежде чем приступить к работе с устаревшим кодом, признать, что все кодовые базы и все команды будут иметь код, который они определяют как «устаревший». И это не вина ни команды, ни конкретного разработчика. Существуют методы поддержки низкого уровня легаси-кода и активного его сокращения, но искоренить весь устаревший код — это неправильная, нереалистичная цель, которая, вероятно, контрпродуктивна для бизнеса и его потребностей.
2. Реалистичный подход к определению легаси-кода
Термин «устаревший код» часто используется, и для команды важно иметь чёткое определение, которое разделяет и понимает каждый. Старый код не обязательно является легаси-кодом. Понятие легаси-кода связано не столько с его возрастом, сколько с характеристиками, которые делают работу над ним сложной и непродуктивной, например:
- Отсутствие автоматизированных тестов. Когда разработчики вносят изменения в этот код, им приходится тестировать его вручную, поскольку не существует автоматического покрытия ни на каком уровне (модульные тесты, интеграционные тесты, сквозные тесты и т. д.).
- Отсутствие документации. Когда разработчикам приходится работать с этим кодом, им сложно его понять. Это может быть связано с тем, что код написан так, что его функциональность становится нечёткой, но на это также влияет отсутствие документации. Это может быть не буквальная документация, а просто контекст того, как он появился: проектный документ с чёткой мотивацией, почему эта функция существует, и стратегией того, как она будет реализована.
- Отсутствие эксперта. Когда команда вносит изменения в код, есть ли человек, который сможет его проверить? Это часто можно заметить по обзорам кода, которые выглядят как быстрое «вроде правильно», потому что рецензенту не хватает контекста и знаний для проведения тщательного анализа. Наиболее вероятный сценарий: рассматриваемый код был написан кем-то, кто покинул команду, и никто больше не работал над этой частью кодовой базы.
Важно чётко понимать, почему с кодом сложно работать и что с этим можно сделать. Просто старый код, но с документацией и тестами, не является устаревшим кодом. Даже код, не имеющий тестов, но с хорошей документацией и известный команде, не обязательно легаси. Ситуацию можно улучшить, просто потратив время на добавление тестов. Тогда у нас будет просто старый, а не легаси-код.
3. Приоритет обновления легаси-кода
Как только код будет обоснованно признан «устаревшим», важно подумать о ценности, которую команда может получить, переписав или обновив код. Может возникнуть соблазн думать об обновлении всего легаси-кода, но это ошибочно. Допустим, есть два блока легаси-кода. Каким заняться в первую очередь?
Определите как часто блок кода должен меняться. Если один блок связан с критически важной функцией, то устаревший статус кода будет иметь огромное влияние, замедляя работу инженеров, снижая удовлетворённость и задерживая релизы.
С другой стороны, если устаревший код находится в блоке, к которому редко прикасаются, не имеет запланированных функций, которые вынудили бы его менять, и всё работает, не создавая проблем для пользователей, какой смысл в переписывании кода?
Планируя инвестиции в устаревший код, сосредотачивайтесь не на технических преимуществах переписывания, а на том, что переписывание даст бизнесу в целом.
Окончание следует…
Источник: https://leaddev.com/legacy-technical-debt-migrations/five-steps-managing-legacy-code
👍13
День 1836. #ЗаметкиНаПолях
Пять Шагов по Управлению Легаси-Кодом. Окончание
Начало
4. Постепенные улучшения
Как подойти к изменению кода? Здесь обычно используются два подхода: переписывание за раз или поэтапно. Как всегда в разработке ПО, серебряной пули не существует. Переписывание за раз рискованно и ставит ряд сложных вопросов:
- Что делать, если обнаружена ошибка? Исправить в старом коде, в новом или и там, и там?
- Что, если переписывание займёт больше времени, чем ожидалось? Придётся ли поддерживать две кодовые базы в течение значительного времени? Приведёт ли это к дублированию работы?
- Что, если нужно выпустить новую функцию по ходу переписывания? Можем ли мы изменять старый код?
- Как выкладывать новую версию? Один большой релиз в конце? Что, если что-то пойдёт не так? Т.е. мы не получим никаких отзывов или ощущения прогресса, пока не выпустим финальную версию?
Поэтапный подход предполагает, что мы делаем ряд мелких шагов к цели. У этого подхода есть свои недостатки (обычно он требует тщательного планирования этапов работы), но он позволяет снизить некоторые из упомянутых ранее рисков:
- Поэтапные релизы проходят легче, чем один большой в конце процесса.
- Мы избегаем создания отдельной базы кода, поэтому не рискуем поддерживать или дублировать работу в двух местах.
- Можно приостановить работу для выпуска новых функций, если необходимо (иногда это приходится делать).
5. Чёткое определение масштаба переписывания
Иногда проект может выйти за рамки поэтапного переписывания и потребовать более агрессивного подхода. При этом важно работать над снижением риска, т.е. жёстко контролировать объём переписывания. Иногда можно переписать всю кодовую базу частями, например, переписать уровень данных, а затем переписывать интерфейс, вместо того чтобы заниматься обеими задачами одновременно. Учитывая, что переписывание обычно требует приостановки каких-либо работ или изменений в оригинале, лучше сводить количество переписываний и их объём к минимуму.
Кроме того, большое переписывание, занимающее недели или месяцы, — это рискованный релиз: в рабочую среду одновременно выбрасывается множество изменений. Вместо этого лучше вносить изменения постепенно, например, скрыв изменения «флагом функции». Так код поставляется, но не выполняется приложением, пока не будет установлен флаг. Затем вы можете включить этот флаг для определённой группы пользователей — например, для внутреннего персонала — и убедиться, что всё работает. Если есть какие-либо проблемы, можно быстро отключить новый код, выключив флаг. Это позволяет оперативно реагировать на неожиданные проблемы (проблемы всегда будут, независимо от того, насколько вы осторожны и старательны). Как только перезапись будет завершена, и вы уверены, что она прошла успешно, можете удалить флаг функции и весь старый код.
Итого
Легаси-код явно никуда не денется. Продукты меняются, команды развиваются, а технологии совершенствуются. Часть кода, который вы пишете сегодня, в ближайшие годы станет устаревшим — и не по вашей вине! Ключевым моментом является умение использовать устаревший код и рассматривать его как интересную техническую задачу. Со временем, работая над этими проблемами, вы накопите массу опыта и инструментов для работы с устаревшим кодом. Вы сможете постепенно модернизировать его с минимальными неудобствами для своих пользователей и коллег, увеличивая охват тестирования, удовлетворённость разработчиков и качество кода. Нет ничего более приятного, чем пул-реквест, который удаляет остатки кода, над переписыванием которого вы работали несколько месяцев.
Источник: https://leaddev.com/legacy-technical-debt-migrations/five-steps-managing-legacy-code
Пять Шагов по Управлению Легаси-Кодом. Окончание
Начало
4. Постепенные улучшения
Как подойти к изменению кода? Здесь обычно используются два подхода: переписывание за раз или поэтапно. Как всегда в разработке ПО, серебряной пули не существует. Переписывание за раз рискованно и ставит ряд сложных вопросов:
- Что делать, если обнаружена ошибка? Исправить в старом коде, в новом или и там, и там?
- Что, если переписывание займёт больше времени, чем ожидалось? Придётся ли поддерживать две кодовые базы в течение значительного времени? Приведёт ли это к дублированию работы?
- Что, если нужно выпустить новую функцию по ходу переписывания? Можем ли мы изменять старый код?
- Как выкладывать новую версию? Один большой релиз в конце? Что, если что-то пойдёт не так? Т.е. мы не получим никаких отзывов или ощущения прогресса, пока не выпустим финальную версию?
Поэтапный подход предполагает, что мы делаем ряд мелких шагов к цели. У этого подхода есть свои недостатки (обычно он требует тщательного планирования этапов работы), но он позволяет снизить некоторые из упомянутых ранее рисков:
- Поэтапные релизы проходят легче, чем один большой в конце процесса.
- Мы избегаем создания отдельной базы кода, поэтому не рискуем поддерживать или дублировать работу в двух местах.
- Можно приостановить работу для выпуска новых функций, если необходимо (иногда это приходится делать).
5. Чёткое определение масштаба переписывания
Иногда проект может выйти за рамки поэтапного переписывания и потребовать более агрессивного подхода. При этом важно работать над снижением риска, т.е. жёстко контролировать объём переписывания. Иногда можно переписать всю кодовую базу частями, например, переписать уровень данных, а затем переписывать интерфейс, вместо того чтобы заниматься обеими задачами одновременно. Учитывая, что переписывание обычно требует приостановки каких-либо работ или изменений в оригинале, лучше сводить количество переписываний и их объём к минимуму.
Кроме того, большое переписывание, занимающее недели или месяцы, — это рискованный релиз: в рабочую среду одновременно выбрасывается множество изменений. Вместо этого лучше вносить изменения постепенно, например, скрыв изменения «флагом функции». Так код поставляется, но не выполняется приложением, пока не будет установлен флаг. Затем вы можете включить этот флаг для определённой группы пользователей — например, для внутреннего персонала — и убедиться, что всё работает. Если есть какие-либо проблемы, можно быстро отключить новый код, выключив флаг. Это позволяет оперативно реагировать на неожиданные проблемы (проблемы всегда будут, независимо от того, насколько вы осторожны и старательны). Как только перезапись будет завершена, и вы уверены, что она прошла успешно, можете удалить флаг функции и весь старый код.
Итого
Легаси-код явно никуда не денется. Продукты меняются, команды развиваются, а технологии совершенствуются. Часть кода, который вы пишете сегодня, в ближайшие годы станет устаревшим — и не по вашей вине! Ключевым моментом является умение использовать устаревший код и рассматривать его как интересную техническую задачу. Со временем, работая над этими проблемами, вы накопите массу опыта и инструментов для работы с устаревшим кодом. Вы сможете постепенно модернизировать его с минимальными неудобствами для своих пользователей и коллег, увеличивая охват тестирования, удовлетворённость разработчиков и качество кода. Нет ничего более приятного, чем пул-реквест, который удаляет остатки кода, над переписыванием которого вы работали несколько месяцев.
Источник: https://leaddev.com/legacy-technical-debt-migrations/five-steps-managing-legacy-code
👍14
День 1837. #Шпаргалка
Примеры Кода для Повседневных Задач
В этой серии представлю вам коллекцию фрагментов кода C#, охватывающих широкий спектр сценариев, с которыми вы можете столкнуться при разработке ПО.
I. Словари
Словари - гибкая структура данных для соединения пар элементов.
1. Объединение двух словарей
Обычная операция при работе со структурами данных. Объединение словарей может оказаться непростой задачей, особенно при наличии повторяющихся ключей. Что делать при этом, будет зависеть от ваших потребностей. Вот несколько примеров:
2. Инвертирование
Что, если вам нужно поменять местами ключи и значения словаря? Операция может осложниться, если у вас неуникальные или нехешируемые значения:
3. Обратный поиск
Обратный поиск (найти ключ для данного значения) может быть полезен, когда словарь слишком велик для инвертирования:
В зависимости от размера словаря и желаемого результата вы можете выбрать наиболее подходящий метод для вашего случая.
Источник: https://medium.com/bytehide/100-csharp-code-snippets-for-everyday-problems-e913c786dec9
Примеры Кода для Повседневных Задач
В этой серии представлю вам коллекцию фрагментов кода C#, охватывающих широкий спектр сценариев, с которыми вы можете столкнуться при разработке ПО.
I. Словари
Словари - гибкая структура данных для соединения пар элементов.
1. Объединение двух словарей
Обычная операция при работе со структурами данных. Объединение словарей может оказаться непростой задачей, особенно при наличии повторяющихся ключей. Что делать при этом, будет зависеть от ваших потребностей. Вот несколько примеров:
var dict1 = new Dictionary<string, string> {
{ "Superman", "Flight" }
};
var dict2 = new Dictionary<string, string> {
{ "Batman", "Gadgets" }
};
// LINQ
var merged = dict1
.Concat(dict2)
.ToDictionary(x => x.Key, x => x.Value);
// Цикл foreach
foreach (var item in dict2)
dict1[item.Key] = item.Value;
// Метод расширения Union
var merged2 = dict1
.Union(dict2)
.ToDictionary(x => x.Key, x => x.Value);
2. Инвертирование
Что, если вам нужно поменять местами ключи и значения словаря? Операция может осложниться, если у вас неуникальные или нехешируемые значения:
var heroes = new Dictionary<string, string>
{
{ "Flash", "Super Speed" },
{ "Green Lantern", "Power Ring" },
{ "Aquaman", "Atlantean Strength" }
};
// LINQ
var inverted = heroes
.ToDictionary(x => x.Value, x => x.Key);
// Цикл foreach
var inverted2 = new Dictionary<string, string>();
foreach (var item in heroes)
inverted2[item.Value] = item.Key;
3. Обратный поиск
Обратный поиск (найти ключ для данного значения) может быть полезен, когда словарь слишком велик для инвертирования:
var dimensions = new Dictionary<string, int>
{
{ "length", 10 },
{ "width", 20 },
{ "height", 30 }
};
int val = 20;
// "В лоб" – первый ключ
foreach (var d in dimensions)
{
if (d.Value == val)
{
Console.WriteLine($"{d.Key}: {d.Value}");
break;
}
}
// "В лоб" – все ключи
foreach (var d in dimensions)
{
if (d.Value == val)
Console.WriteLine($"{d.Key}: {d.Value}");
}
// LINQ – первый ключ
var key = dimensions
.FirstOrDefault(x => x.Value == val)
.Key;
// LINQ – все ключи
var keys = dimensions
.Where(x => x.Value == val)
.Select(x => x.Key);
В зависимости от размера словаря и желаемого результата вы можете выбрать наиболее подходящий метод для вашего случая.
Источник: https://medium.com/bytehide/100-csharp-code-snippets-for-everyday-problems-e913c786dec9
👍17👎3
День 1838. #ProjectManagement
Чтобы Избавиться Технического Долга, Оцените Его. Начало
Когда Уорд Каннингем придумал метафору технического долга, ему нужен был способ обсудить решения, принятые на ранних этапах проекта, которые мешали инженерам в дальнейшей работе над проектом. Он занимался финансовым ПО - отсюда финансовая метафора. Технические решения, которые команда приняла на раннем этапе ради вывода продукта на рынок, возможно, вредят впоследствии, и, если их не исправить, производительность команды пострадает, а новые функции будут выпускаться медленнее.
Многие успешные компании использовали технологический долг, чтобы начать работу, только чтобы погасить его позже. Например, Facebook изначально был написан на PHP. Стоит отметить, что техдолг не обязательно означает, что первоначальный выбор был ошибочным. Написание сайта на PHP поначалу не было плохим решением — это не тот случай, когда плохой код в дальнейшем им мешал. Это прекрасный язык, который Facebook просто перерос.
На самом деле, проблема обновления устаревшего фреймворка или библиотеки не является технической. Как и в метафоре, она финансовая. Множество обновлений откладываются на долгие годы из-за необходимости установки нового ПО, переписывания кода и проверки последствий обновления. При этом неисправленные дыры в безопасности могут сделать проект уязвимым, а сложность выпуска новых функций может поставить приложение в невыгодное положение на рынке. Когда-нибудь этот счёт придётся оплатить.
Технический долг – это не только обновления языка и инструментов. Это могут быть добросовестные решения при написании кода, принятые ради немедленной выгоды. Чем раньше вы сможете вернуть долги, тем лучше. Но возврат долгов требует точного определения размера долга, который несёт команда.
Стоимость времени обслуживания
Разработчики любят решать проблемы, но эта любовь не всегда распространяется на поиск ошибок и замену устаревших технологий. Однако, какие тикеты попадут в следующий спринт, определяет менеджмент. Разработчики могут стремиться писать наиболее элегантный и чистый код, но менеджер служит бизнесу, а бизнес часто фокусируется на прибылях и убытках. Чтобы погасить технологический долг, сначала необходимо оценить его с точки зрения затрат и выгод.
Экономические последствия технического долга вполне реальны. В 2018 году Stripe провела исследование влияния техдолга и других эффектов «плохого кода». Они обнаружили, что средний разработчик в неделю тратил 13,5 часов на техдолг и ещё почти 4 часа на «плохой код». Т.е. почти половину рабочего времени! Если вы умножите это на зарплату разработчика, то получите серьёзные затраты на техдолг.
Поддержка некачественного кода часто занимает значительно больше времени из-за сложности, а также обычно влечёт больше ошибок. Таким образом, низкое качество в итоге серьёзно влияет на то, что ценят менеджеры. Большинство компаний уже используют какую-либо систему отслеживания проблем, поэтому разработчики, которые хотят обосновать стремление избавиться от техдолга, могут использовать её. Это просто требует дисциплины в отслеживании тикетов, оценке стори-пойнтов и подтверждении времени, потраченного на обслуживание техдолга.
Также можно просто спросить команду. Если команда признаёт что-то важным, они, вероятно, либо потратили некоторое время на это недавно (т.е. это свежо у них в голове), либо код настолько плох, что работа над ним надолго запомнилась.
Описанное выше - это всего лишь затраты на написание кода для избавления от техдолга. Ещё одна важная метрика — это код, который вы НЕ написали.
Окончание следует…
Источник: https://stackoverflow.blog/2023/08/24/if-you-want-to-address-tech-debt-quantify-it-first/
Чтобы Избавиться Технического Долга, Оцените Его. Начало
Когда Уорд Каннингем придумал метафору технического долга, ему нужен был способ обсудить решения, принятые на ранних этапах проекта, которые мешали инженерам в дальнейшей работе над проектом. Он занимался финансовым ПО - отсюда финансовая метафора. Технические решения, которые команда приняла на раннем этапе ради вывода продукта на рынок, возможно, вредят впоследствии, и, если их не исправить, производительность команды пострадает, а новые функции будут выпускаться медленнее.
Многие успешные компании использовали технологический долг, чтобы начать работу, только чтобы погасить его позже. Например, Facebook изначально был написан на PHP. Стоит отметить, что техдолг не обязательно означает, что первоначальный выбор был ошибочным. Написание сайта на PHP поначалу не было плохим решением — это не тот случай, когда плохой код в дальнейшем им мешал. Это прекрасный язык, который Facebook просто перерос.
На самом деле, проблема обновления устаревшего фреймворка или библиотеки не является технической. Как и в метафоре, она финансовая. Множество обновлений откладываются на долгие годы из-за необходимости установки нового ПО, переписывания кода и проверки последствий обновления. При этом неисправленные дыры в безопасности могут сделать проект уязвимым, а сложность выпуска новых функций может поставить приложение в невыгодное положение на рынке. Когда-нибудь этот счёт придётся оплатить.
Технический долг – это не только обновления языка и инструментов. Это могут быть добросовестные решения при написании кода, принятые ради немедленной выгоды. Чем раньше вы сможете вернуть долги, тем лучше. Но возврат долгов требует точного определения размера долга, который несёт команда.
Стоимость времени обслуживания
Разработчики любят решать проблемы, но эта любовь не всегда распространяется на поиск ошибок и замену устаревших технологий. Однако, какие тикеты попадут в следующий спринт, определяет менеджмент. Разработчики могут стремиться писать наиболее элегантный и чистый код, но менеджер служит бизнесу, а бизнес часто фокусируется на прибылях и убытках. Чтобы погасить технологический долг, сначала необходимо оценить его с точки зрения затрат и выгод.
Экономические последствия технического долга вполне реальны. В 2018 году Stripe провела исследование влияния техдолга и других эффектов «плохого кода». Они обнаружили, что средний разработчик в неделю тратил 13,5 часов на техдолг и ещё почти 4 часа на «плохой код». Т.е. почти половину рабочего времени! Если вы умножите это на зарплату разработчика, то получите серьёзные затраты на техдолг.
Поддержка некачественного кода часто занимает значительно больше времени из-за сложности, а также обычно влечёт больше ошибок. Таким образом, низкое качество в итоге серьёзно влияет на то, что ценят менеджеры. Большинство компаний уже используют какую-либо систему отслеживания проблем, поэтому разработчики, которые хотят обосновать стремление избавиться от техдолга, могут использовать её. Это просто требует дисциплины в отслеживании тикетов, оценке стори-пойнтов и подтверждении времени, потраченного на обслуживание техдолга.
Также можно просто спросить команду. Если команда признаёт что-то важным, они, вероятно, либо потратили некоторое время на это недавно (т.е. это свежо у них в голове), либо код настолько плох, что работа над ним надолго запомнилась.
Описанное выше - это всего лишь затраты на написание кода для избавления от техдолга. Ещё одна важная метрика — это код, который вы НЕ написали.
Окончание следует…
Источник: https://stackoverflow.blog/2023/08/24/if-you-want-to-address-tech-debt-quantify-it-first/
👍11
День 1839. #ProjectManagement
Чтобы Избавиться Технического Долга, Оцените Его. Окончание
Начало
Стоимость возможностей
Если разработчики тратят время на техдолг и плохой код, значит они не предоставляют новые функции. В индустрии ПО чем быстрее вы сможете внедрять новые функции, тем лучше сможете удовлетворять требования клиентов и большую ценность добавите продукту.
Техдолг влияет на то, сколько времени потребуется на написание нового кода, особенно если, избегая избавления от техдолга, вы добавляете костыли, которые увеличивают количество путей прохождения кода (цикломатическую сложность). Эта сложность сама по себе становится частью долга, который придётся в какой-то момент оплатить.
Существует связь между этой сложностью и продуктивностью разработчиков. Т.к. код становится сложнее поддерживать, новые функции занимают больше времени. Чем больше мест в коде необходимо затронуть, чтобы изменение заработало, тем больше времени это занимает.
Иногда техдолг возникает из-за добросовестных решений, которые устарели или основаны на старых версиях ПО. Их обновление может потребовать серьёзного переписывания, а не просто рефакторинга. Вот несколько признаков того, что код требуется переписать:
- ПО устарело или скоро потеряет поддержку, или доступна версия лучше.
- Вы не можете автоматизировать развёртывание.
- Тестирование занимает слишком много времени, не может быть автоматизировано или не может охватить важные функции.
Если у вас есть такая статистика, вы можете сравнить вашу текущую скорость выпуска новых функций с лучшим спринтом, который часто приходится на начало жизненного цикла ПО. Разницу можно считать процентами по техническому долгу. По мере роста долга растут и время, и усилия, затрачиваемые на погашение этих процентов. Чем медленнее общая скорость разработки, тем меньше новых функций будет поставлено клиентам.
Человеческая стоимость
Компании конкурируют за лучшие технические таланты. Трудоустройство нового сотрудника может стоить от шести до девяти его зарплат. Потому компаний уделяют особое внимание опыту адаптации разработчиков.
Адаптация — первая и самая важная часть опыта сотрудника в компании. Чтобы освоиться новому сотруднику может потребоваться до двух месяцев. Неудачный опыт адаптации может отпугнуть разработчика. 20% уходят в течение первых 45 дней. Т.е. плавный процесс адаптации может означать разницу между получением хорошего специалиста и новым поиском.
Время адаптации разработчика будет зависеть как от имеющейся документации и налаженных процессов, так и от сложности и читаемости кода. Отсутствие документации тоже форма долга. Вы знаете, что в какой-то момент она вам понадобится, но, чтобы двигаться быстрее, вы не стали её писать. Новым сотрудникам придётся расспрашивать и тратить время старших инженеров, чтобы адаптироваться.
Новый разработчик может разочароваться, увидев методы написания кода, принятые в команде, которые затрудняют анализ кода. Это расстраивает и деморализует, поскольку вы постоянно тратите время, пытаясь понять, что происходит в коде.
Очевидно, техдолг — не просто код, который требует рефакторинга для соответствия лучшим практикам: устаревшие или неэффективные инструменты и зависимости тоже считаются. В опросе StackOverflow о том, почему разработчики решают остаться на работе или уйти 35-40% сказали, что ищут новую работу, чтобы использовать новые технологии.
Т.е., если ваша компания страдает от частых уходов людей в течение первого года, то возможно проблема в техдолге. Проводите выходные интервью и отслеживайте отзывы. Если долг стоит вам хороших сотрудников, это веская причина пересмотреть приоритеты в следующем спринте.
Источник: https://stackoverflow.blog/2023/08/24/if-you-want-to-address-tech-debt-quantify-it-first/
Чтобы Избавиться Технического Долга, Оцените Его. Окончание
Начало
Стоимость возможностей
Если разработчики тратят время на техдолг и плохой код, значит они не предоставляют новые функции. В индустрии ПО чем быстрее вы сможете внедрять новые функции, тем лучше сможете удовлетворять требования клиентов и большую ценность добавите продукту.
Техдолг влияет на то, сколько времени потребуется на написание нового кода, особенно если, избегая избавления от техдолга, вы добавляете костыли, которые увеличивают количество путей прохождения кода (цикломатическую сложность). Эта сложность сама по себе становится частью долга, который придётся в какой-то момент оплатить.
Существует связь между этой сложностью и продуктивностью разработчиков. Т.к. код становится сложнее поддерживать, новые функции занимают больше времени. Чем больше мест в коде необходимо затронуть, чтобы изменение заработало, тем больше времени это занимает.
Иногда техдолг возникает из-за добросовестных решений, которые устарели или основаны на старых версиях ПО. Их обновление может потребовать серьёзного переписывания, а не просто рефакторинга. Вот несколько признаков того, что код требуется переписать:
- ПО устарело или скоро потеряет поддержку, или доступна версия лучше.
- Вы не можете автоматизировать развёртывание.
- Тестирование занимает слишком много времени, не может быть автоматизировано или не может охватить важные функции.
Если у вас есть такая статистика, вы можете сравнить вашу текущую скорость выпуска новых функций с лучшим спринтом, который часто приходится на начало жизненного цикла ПО. Разницу можно считать процентами по техническому долгу. По мере роста долга растут и время, и усилия, затрачиваемые на погашение этих процентов. Чем медленнее общая скорость разработки, тем меньше новых функций будет поставлено клиентам.
Человеческая стоимость
Компании конкурируют за лучшие технические таланты. Трудоустройство нового сотрудника может стоить от шести до девяти его зарплат. Потому компаний уделяют особое внимание опыту адаптации разработчиков.
Адаптация — первая и самая важная часть опыта сотрудника в компании. Чтобы освоиться новому сотруднику может потребоваться до двух месяцев. Неудачный опыт адаптации может отпугнуть разработчика. 20% уходят в течение первых 45 дней. Т.е. плавный процесс адаптации может означать разницу между получением хорошего специалиста и новым поиском.
Время адаптации разработчика будет зависеть как от имеющейся документации и налаженных процессов, так и от сложности и читаемости кода. Отсутствие документации тоже форма долга. Вы знаете, что в какой-то момент она вам понадобится, но, чтобы двигаться быстрее, вы не стали её писать. Новым сотрудникам придётся расспрашивать и тратить время старших инженеров, чтобы адаптироваться.
Новый разработчик может разочароваться, увидев методы написания кода, принятые в команде, которые затрудняют анализ кода. Это расстраивает и деморализует, поскольку вы постоянно тратите время, пытаясь понять, что происходит в коде.
Очевидно, техдолг — не просто код, который требует рефакторинга для соответствия лучшим практикам: устаревшие или неэффективные инструменты и зависимости тоже считаются. В опросе StackOverflow о том, почему разработчики решают остаться на работе или уйти 35-40% сказали, что ищут новую работу, чтобы использовать новые технологии.
Т.е., если ваша компания страдает от частых уходов людей в течение первого года, то возможно проблема в техдолге. Проводите выходные интервью и отслеживайте отзывы. Если долг стоит вам хороших сотрудников, это веская причина пересмотреть приоритеты в следующем спринте.
Источник: https://stackoverflow.blog/2023/08/24/if-you-want-to-address-tech-debt-quantify-it-first/
👍14