Виды Классов в C#
Абстрактный
Базовый класс, экземпляр которого нельзя создать. Он может содержать абстрактные и неабстрактные члены и предназначен для наследования от него.
Создать экземпляр класса Vehicle нельзя, поэтому унаследуем от него. При этом класс-наследник обязан переопределить абстрактные члены:
Запечатанный (sealed)
Специальный тип класса, который ограничивает иерархию наследования. Это предотвращает создание производных типов, что повышает безопасность кода и позволяет компилятору применять оптимизации производительности.
Статический
Экземпляр статического класса нельзя создать, и от статического класса нельзя унаследовать. Все члены должны быть помечены статическими.
Частичный
В одном и том же пространстве имён нельзя создавать несколько классов с одним именем. Частичный класс позволяет разделить объявление класса на несколько файлов. При компиляции объявления объединяются в один класс. Нельзя дублировать члены с одной сигнатурой в разных объявлениях частичного класса:
Небезопасный
Небезопасный класс позволяет использовать код с указателями:
Если вам необходимо работать с указателями, нужно включить небезопасный код в файле .csproj, установив параметр AllowUnsafeBlocks в значение true.
Запись
Запись — ссылочный тип, предназначенный для данных, а не для поведения, и по умолчанию является неизменяемой:
Модификаторы доступа
-
-
-
-
-
👉 @KodBlog
Абстрактный
Базовый класс, экземпляр которого нельзя создать. Он может содержать абстрактные и неабстрактные члены и предназначен для наследования от него.
public abstract class Vehicle
{
public abstract int Wheels { get; }
public abstract void TurnOn();
public bool Started { get; protected set; }
}
Создать экземпляр класса Vehicle нельзя, поэтому унаследуем от него. При этом класс-наследник обязан переопределить абстрактные члены:
public class Car : Vehicle
{
public override int Wheels => 4;
public override void TurnOn()
=> Started = true;
}
Запечатанный (sealed)
Специальный тип класса, который ограничивает иерархию наследования. Это предотвращает создание производных типов, что повышает безопасность кода и позволяет компилятору применять оптимизации производительности.
public sealed class Vehicle
{
}
Статический
Экземпляр статического класса нельзя создать, и от статического класса нельзя унаследовать. Все члены должны быть помечены статическими.
public static class SpeedConverter
{
public static decimal ToMph(decimal kph)
=> return kph / 1.6093m;
}
Частичный
В одном и том же пространстве имён нельзя создавать несколько классов с одним именем. Частичный класс позволяет разделить объявление класса на несколько файлов. При компиляции объявления объединяются в один класс. Нельзя дублировать члены с одной сигнатурой в разных объявлениях частичного класса:
public partial class Team
{
public Team() { }
public string Name { get; set; }
}
public partial class Team
{
public int Players { get; set; }
}
Небезопасный
Небезопасный класс позволяет использовать код с указателями:
public unsafe class MemoryReader
{
public void Read(int* value)
{
Console.WriteLine(*value);
}
}
Если вам необходимо работать с указателями, нужно включить небезопасный код в файле .csproj, установив параметр AllowUnsafeBlocks в значение true.
Запись
Запись — ссылочный тип, предназначенный для данных, а не для поведения, и по умолчанию является неизменяемой:
public record class Team(string Name, int Players);
Модификаторы доступа
-
public – доступен отовсюду;-
internal – доступен внутри сборки;-
private – доступен только внутри включающего его типа;-
protected – доступен внутри включающего его типа и всех его наследников;-
file – доступен только внутри содержащего его файла исходного кода.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9❤4🍾2😁1🤯1
This media is not supported in your browser
VIEW IN TELEGRAM
Чилловый разработчик сделал “чёрную дыру” прямо в терминале, чтобы заставить себя делать перерывы.
Чем дольше работаешь без остановки, тем больше она растёт и начинает искажать код, как гравитационная линза.
Отдохнул — она уменьшается.
👉 @KodBlog
Чем дольше работаешь без остановки, тем больше она растёт и начинает искажать код, как гравитационная линза.
Отдохнул — она уменьшается.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥17👍8❤1👎1🍾1
Что Происходит, Когда вы Вводите google.com в Браузере?
1. Вы вводите адрес веб-сайта в адресную строку браузера.
2. Браузер сначала проверяет свой кэш. Если адрес не найден в кэше, он должен найти IP-адрес.
3. Начинается поиск DNS (представьте, что вы ищете номер телефона). Запрос проходит через различные DNS-серверы (корневой, TLD - сервер имен доменов верхнего уровня - и авторитативный). Наконец, извлекается IP-адрес.
4. Браузер инициирует TCP-соединение, начиная с рукопожатия. Например, в случае HTTP 1.1 клиент и сервер выполняют трёхстороннее TCP-рукопожатие с сообщениями SYN, SYN-ACK и ACK.
5. Браузер отправляет HTTP-запрос на сервер, и сервер отвечает файлами HTML, CSS и JS.
6. Браузер обрабатывает ответ. Он анализирует HTML-документ и создаёт деревья DOM и CSSOM.
7. Браузер выполняет код JavaScript и отображает страницу, проходя через различные этапы (токенизатор, парсер, дерево рендеринга, компоновка и отрисовка).
8. Веб-страница появляется на экране.
👉 @KodBlog
1. Вы вводите адрес веб-сайта в адресную строку браузера.
2. Браузер сначала проверяет свой кэш. Если адрес не найден в кэше, он должен найти IP-адрес.
3. Начинается поиск DNS (представьте, что вы ищете номер телефона). Запрос проходит через различные DNS-серверы (корневой, TLD - сервер имен доменов верхнего уровня - и авторитативный). Наконец, извлекается IP-адрес.
4. Браузер инициирует TCP-соединение, начиная с рукопожатия. Например, в случае HTTP 1.1 клиент и сервер выполняют трёхстороннее TCP-рукопожатие с сообщениями SYN, SYN-ACK и ACK.
5. Браузер отправляет HTTP-запрос на сервер, и сервер отвечает файлами HTML, CSS и JS.
6. Браузер обрабатывает ответ. Он анализирует HTML-документ и создаёт деревья DOM и CSSOM.
7. Браузер выполняет код JavaScript и отображает страницу, проходя через различные этапы (токенизатор, парсер, дерево рендеринга, компоновка и отрисовка).
8. Веб-страница появляется на экране.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥4❤3🍾1
Вышел Rider 2026.2 EAP 6.
В этом превью JetBrains улучшили отображение асинхронных стеков вызовов во время отладки.
Теперь отладчик скрывает часть шума от сгенерированных кадров, связанных с
👉 @KodBlog
В этом превью JetBrains улучшили отображение асинхронных стеков вызовов во время отладки.
Теперь отладчик скрывает часть шума от сгенерированных кадров, связанных с
async/await и инфраструктурой Task, поэтому проще отслеживать реальный поток выполнения приложения, не продираясь через детали реализации, добавленные компилятором.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👍5🤔3🍾2
Небольшой совет по написанию чистого кода:
Заменяйте сложные
Сложные
Особенно когда они объединяют несколько разных условий.
Это можно исправить простым рефакторингом.
→ Вынесите условие в метод или переменную с говорящим именем.
Теперь само название объясняет, что именно проверяется.
Людям гораздо проще читать понятные названия, чем разбирать сложные условия в коде.
👉 @KodBlog
Заменяйте сложные
if-условия методами с понятными названиями.Сложные
if-ы тяжело читать.Особенно когда они объединяют несколько разных условий.
Это можно исправить простым рефакторингом.
→ Вынесите условие в метод или переменную с говорящим именем.
Теперь само название объясняет, что именно проверяется.
Людям гораздо проще читать понятные названия, чем разбирать сложные условия в коде.
Please open Telegram to view this post
VIEW IN TELEGRAM
👏9👍3❤2🔥2🍾1
Виртуальная машина vs Контейнер vs Serverless
Виртуальные машины запускают полноценную операционную систему поверх виртуализированного оборудования. Они обеспечивают высокий уровень изоляции и дают больше контроля над окружением, но требуют больше ресурсов, поскольку каждая ВМ содержит собственную ОС.
Контейнеры упаковывают приложение вместе со всеми его зависимостями и запускаются как изолированные процессы на общем ядре хостовой системы. Они легче виртуальных машин, проще переносятся между окружениями и широко используются для развертывания микросервисов.
Serverless-функции позволяют развёртывать небольшие фрагменты кода без управления базовой серверной инфраструктурой. Облачный провайдер берёт на себя выделение ресурсов, масштабирование и выполнение кода, поэтому такой подход хорошо подходит для событийно-ориентированных задач: API, задач по расписанию и обработки очередей.
В современных системах редко выбирают только один из этих подходов. Часто контейнеры работают внутри виртуальных машин, а serverless-функции используются для отдельных событийно-ориентированных сценариев, где каждая технология применяется для тех нагрузок, которым она подходит лучше всего.
👉 @KodBlog
Виртуальные машины запускают полноценную операционную систему поверх виртуализированного оборудования. Они обеспечивают высокий уровень изоляции и дают больше контроля над окружением, но требуют больше ресурсов, поскольку каждая ВМ содержит собственную ОС.
Контейнеры упаковывают приложение вместе со всеми его зависимостями и запускаются как изолированные процессы на общем ядре хостовой системы. Они легче виртуальных машин, проще переносятся между окружениями и широко используются для развертывания микросервисов.
Serverless-функции позволяют развёртывать небольшие фрагменты кода без управления базовой серверной инфраструктурой. Облачный провайдер берёт на себя выделение ресурсов, масштабирование и выполнение кода, поэтому такой подход хорошо подходит для событийно-ориентированных задач: API, задач по расписанию и обработки очередей.
В современных системах редко выбирают только один из этих подходов. Часто контейнеры работают внутри виртуальных машин, а serverless-функции используются для отдельных событийно-ориентированных сценариев, где каждая технология применяется для тех нагрузок, которым она подходит лучше всего.
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾3❤1
Перед тем как читать новый проект, я первым делом иду не в код, а в Git.
Пара команд за 2 минуты часто рассказывает о кодовой базе больше, чем час листания файлов.
Что меняют чаще всего
Показывает 20 файлов, которые меняли чаще всего за последний год. Верхние строчки списка обычно быстро находят тот самый файл, к которому все боятся прикасаться.
Кто реально поддерживает проект
Сразу видно распределение коммитов между разработчиками и потенциальный автобусный фактор.
Где чаще всего чинят баги
Если файл часто появляется и здесь, и в списке самых изменяемых файлов — это один из главных источников технического долга.
Проект набирает темп или затухает
Количество коммитов по месяцам помогает быстро понять динамику разработки.
Как часто приходится тушить пожары
Откаты, хотфиксы и экстренные исправления многое говорят о качестве релизного процесса.
Эти команды не заменят аудит, но помогают понять, какие части системы стоит изучать в первую очередь, а какие проблемы уже давно кричат о себе через историю Git.
👉 @KodBlog
Пара команд за 2 минуты часто рассказывает о кодовой базе больше, чем час листания файлов.
Что меняют чаще всего
git log --format=format: --name-only --since="1 year ago" | sort | uniq -c | sort -nr | head -20
Показывает 20 файлов, которые меняли чаще всего за последний год. Верхние строчки списка обычно быстро находят тот самый файл, к которому все боятся прикасаться.
Кто реально поддерживает проект
git shortlog -sn --no-merges
Сразу видно распределение коммитов между разработчиками и потенциальный автобусный фактор.
Где чаще всего чинят баги
git log -i -E --grep="fix|bug|broken" --name-only --format='' | sort | uniq -c | sort -nr | head -20
Если файл часто появляется и здесь, и в списке самых изменяемых файлов — это один из главных источников технического долга.
Проект набирает темп или затухает
git log --format='%ad' --date=format:'%Y-%m' | sort | uniq -c
Количество коммитов по месяцам помогает быстро понять динамику разработки.
Как часто приходится тушить пожары
git log --oneline --since="1 year ago" | grep -iE 'revert|hotfix|emergency|rollback'
Откаты, хотфиксы и экстренные исправления многое говорят о качестве релизного процесса.
Эти команды не заменят аудит, но помогают понять, какие части системы стоит изучать в первую очередь, а какие проблемы уже давно кричат о себе через историю Git.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥17❤4💯4🍾1
Вышел roadmap для SqlClient
https://github.com/dotnet/SqlClient/blob/main/roadmap.md
Стоит посмотреть, если тебе интересны:
- особенности работы пула соединений (connection pooling)
- сценарии аутентификации (Entra ID, MSI и другие)
- производительность и надёжность под высокой нагрузкой
На этом этапе обратная связь от сообщества ещё может повлиять на архитектурные и технические решения.
#dotnet #sqlserver
👉 @KodBlog
https://github.com/dotnet/SqlClient/blob/main/roadmap.md
Стоит посмотреть, если тебе интересны:
- особенности работы пула соединений (connection pooling)
- сценарии аутентификации (Entra ID, MSI и другие)
- производительность и надёжность под высокой нагрузкой
На этом этапе обратная связь от сообщества ещё может повлиять на архитектурные и технические решения.
#dotnet #sqlserver
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
SqlClient/roadmap.md at main · dotnet/SqlClient
Microsoft.Data.SqlClient provides database connectivity to SQL Server for .NET applications. - dotnet/SqlClient
🍾1
Создаём Базовый Компонент для Всех Компонентов в Blazor
При разработке Blazor-приложения может понадобиться пользовательский базовый компонент для всех остальных компонентов. Это полезно для совместного использования общих функций, таких как токены отмены, логирование или управление состоянием, во всех компонентах. Вместо добавления
Создадим файл
Файл
Пример: CustomComponentBase с CancellationToken
Вот пример базового компонента, который предоставляет CancellationToken всем производным компонентам. Это полезно для отмены асинхронных операций при удалении компонента:
Теперь все наши компоненты могут получить доступ к свойству CancellationToken без какой-либо дополнительной настройки:
Переопределение базового компонента для конкретных компонентов
Если конкретному компоненту требуется другой базовый компонент или вообще никакой, вы можете объявить @inherits непосредственно в файле этого компонента. Явное объявление имеет приоритет над _Imports.razor:
Организация файлов _Imports.razor
Можно иметь несколько файлов
👉 @KodBlog
При разработке Blazor-приложения может понадобиться пользовательский базовый компонент для всех остальных компонентов. Это полезно для совместного использования общих функций, таких как токены отмены, логирование или управление состоянием, во всех компонентах. Вместо добавления
@inherits YourBaseComponent в каждый файл Razor, вы можете использовать файл _Imports.razor для глобальной установки базового компонента.Создадим файл
_Imports.razor в папке, к компонентам которой нужно применить базовый компонент. Все файлы Razor в этой папке и её подпапках будут наследовать указанный базовый компонент.@inherits YourNamespace.CustomComponentBase
Файл
_Imports.razor обрабатывается перед любым компонентом Razor в том же каталоге или его подкаталогах. Все компоненты затем автоматически наследуют от CustomComponentBase без необходимости объявлять @inherits в каждом файле.Пример: CustomComponentBase с CancellationToken
Вот пример базового компонента, который предоставляет CancellationToken всем производным компонентам. Это полезно для отмены асинхронных операций при удалении компонента:
@* CustomComponentBase.razor (Razor) *@
@implements IDisposable
@code {
private readonly CancellationTokenSource
_cts = new CancellationTokenSource();
public CancellationToken
CancellationToken => _cts.Token;
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
}
Теперь все наши компоненты могут получить доступ к свойству CancellationToken без какой-либо дополнительной настройки:
@* MyComponent.razor (Razor) *@
@* Не нужно использовать @inherits, т.к. _Imports.razor импортируется автоматически *@
<h3>Мой компонент</h3>
@code {
protected override async Task OnInitializedAsync()
{
// Используем CancellationToken из базового компонента
await LoadDataAsync(CancellationToken);
}
private async Task LoadDataAsync(CancellationToken ct)
{
// … асинхронный код …
await Task.Delay(1000, ct);
}
}
Переопределение базового компонента для конкретных компонентов
Если конкретному компоненту требуется другой базовый компонент или вообще никакой, вы можете объявить @inherits непосредственно в файле этого компонента. Явное объявление имеет приоритет над _Imports.razor:
@* MyComponent.razor (Razor) *@
@inherits ComponentBase
@* Этот компонент будет использовать ComponentBase вместо CustomComponentBase *@
Организация файлов _Imports.razor
Можно иметь несколько файлов
_Imports.razor в разных папках, чтобы применять разные базовые компоненты к различным разделам приложения. Приоритет имеет ближайший файл _Imports.razor в иерархии каталогов. Например, /Components/_Imports.razor применяется ко всем компонентам в этой папке /Components/Admin/_Imports.razor применяется специально к компонентам папки Admin. Такой иерархический подход обеспечивает точный контроль над тем, какие компоненты наследуют от каких базовых классов.Please open Telegram to view this post
VIEW IN TELEGRAM
👏6❤1🍾1
Вопрос с C#-собеседования уровня Middle/Senior.
Многие разработчики на нём ошибаются
Посмотрите на код на первом слайде.
Что там видно:
мы проходимся по элементам в цикле;
внутри цикла используется
Так почему всё равно появляется warning или error?
Подумайте немного... А потом откройте второй слайд и проверьте свой ответ.
Ответ 👇
В отличие от обычного
После этого выполнение продолжается с того места, где оно было остановлено.
Поэтому, если нужно пропустить текущую итерацию, следует использовать
Иначе код после
Это одна из тех особенностей C#, о которых часто забывают даже опытные разработчики.
👉 @KodBlog
Многие разработчики на нём ошибаются
Посмотрите на код на первом слайде.
Что там видно:
ProductStock не равен null;мы проходимся по элементам в цикле;
внутри цикла используется
yield return.Так почему всё равно появляется warning или error?
Подумайте немного... А потом откройте второй слайд и проверьте свой ответ.
Ответ 👇
yield return не останавливает выполнение цикла.В отличие от обычного
return, который сразу завершает метод, yield return лишь приостанавливает выполнение и возвращает очередной элемент последовательности.После этого выполнение продолжается с того места, где оно было остановлено.
Поэтому, если нужно пропустить текущую итерацию, следует использовать
continue.Иначе код после
yield return всё равно выполнится, что может привести к неожиданному поведению или исключениям.Это одна из тех особенностей C#, о которых часто забывают даже опытные разработчики.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥14❤5🍾2
Практическое применение архитектуры Vertical Slice в ASP.NET Core
https://www.telerik.com/blogs/practicing-vertical-slice-architecture-aspnet-core
Автор: Assis Zang
#aspnetcore
👉 @KodBlog
https://www.telerik.com/blogs/practicing-vertical-slice-architecture-aspnet-core
Автор: Assis Zang
#aspnetcore
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5🍾1
Перестаньте использовать исключения для управления логикой приложения
Вот почему 👇
Большинство разработчиков используют исключения каждый день.
Но есть проблема: исключения подходят далеко не для всех сценариев.
Работая архитектором ПО и .NET-разработчиком, я пришёл к простому выводу:
Использование исключений для управления потоком выполнения делает код сложнее для чтения, тестирования и сопровождения.
👉 Исключения нужны для обработки действительно нештатных ситуаций.
Но ими не стоит заменять обычную бизнес-логику и ожидаемые условия.
Основные недостатки такого подхода:
• Непредсказуемость — по сигнатуре метода не всегда понятно, какие исключения он может выбросить
• Снижение читаемости — try/catch ломает линейный поток чтения кода
• Вложенность — отладка и навигация по коду становятся менее удобными
• Потери производительности — обработка исключений обходится дороже обычных проверок (даже с улучшениями в .NET 9)
Что использовать вместо этого?
✅ Result Pattern
Вместо выбрасывания исключений метод возвращает объект Result.
Так успех и ошибка становятся явной частью контракта метода.
📌 Обычно объект Result содержит:
1️⃣ IsSuccess / IsError — успешно ли выполнена операция
2️⃣ Value — результат выполнения при успехе
3️⃣ Error — информация об ошибке при неудаче
Плюсы такого подхода:
↳ Более предсказуемые API
↳ Более чистый поток выполнения
↳ Проще писать unit-тесты
↳ Лучше производительность
Для этого паттерна уже есть готовые библиотеки:
• FluentResults
• CSharpFunctionalExtensions
• Ardalis.Result
• ErrorOr
Но на практике сторонние пакеты вовсе не обязательны.
👉 @KodBlog
Вот почему 👇
Большинство разработчиков используют исключения каждый день.
Но есть проблема: исключения подходят далеко не для всех сценариев.
Работая архитектором ПО и .NET-разработчиком, я пришёл к простому выводу:
Использование исключений для управления потоком выполнения делает код сложнее для чтения, тестирования и сопровождения.
👉 Исключения нужны для обработки действительно нештатных ситуаций.
Но ими не стоит заменять обычную бизнес-логику и ожидаемые условия.
Основные недостатки такого подхода:
• Непредсказуемость — по сигнатуре метода не всегда понятно, какие исключения он может выбросить
• Снижение читаемости — try/catch ломает линейный поток чтения кода
• Вложенность — отладка и навигация по коду становятся менее удобными
• Потери производительности — обработка исключений обходится дороже обычных проверок (даже с улучшениями в .NET 9)
Что использовать вместо этого?
✅ Result Pattern
Вместо выбрасывания исключений метод возвращает объект Result.
Так успех и ошибка становятся явной частью контракта метода.
📌 Обычно объект Result содержит:
1️⃣ IsSuccess / IsError — успешно ли выполнена операция
2️⃣ Value — результат выполнения при успехе
3️⃣ Error — информация об ошибке при неудаче
Плюсы такого подхода:
↳ Более предсказуемые API
↳ Более чистый поток выполнения
↳ Проще писать unit-тесты
↳ Лучше производительность
Для этого паттерна уже есть готовые библиотеки:
• FluentResults
• CSharpFunctionalExtensions
• Ardalis.Result
• ErrorOr
Но на практике сторонние пакеты вовсе не обязательны.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🥴5🔥1🍾1
Как работает git?
На изображении схематично изображён процесс работы с Git — системой контроля версий.
Workspace: Рабочее пространство, где находятся файлы проекта (например, .git, src, index.html).
🟢 Команда git add перемещает изменения в Stage (область индексации).
🟢 Команда git reset отменяет индексацию изменений.
Stage: Область индексации, где изменения подготавливаются для фиксации.
🟢 Команда git commit сохраняет изменения в локальном репозитории.
Local Repository: Локальный репозиторий, где хранятся зафиксированные изменения.
🟢 Команда git push отправляет изменения в удалённый репозиторий.
Remote Repository: Удалённый репозиторий, например, на платформах GitLab, GitHub или Bitbucket.
🟢 Команда git fetch извлекает изменения с удалённого репозитория.
🟢 Команда git pull объединяет изменения удалённого и локального репозиториев (эквивалентно git fetch + git merge).
В нижней части схемы представлена последовательность действий при выполнении команды git pull.😮
Эта схема полезна для понимания основных этапов работы с Git.
👉 @KodBlog
На изображении схематично изображён процесс работы с Git — системой контроля версий.
Workspace: Рабочее пространство, где находятся файлы проекта (например, .git, src, index.html).
Stage: Область индексации, где изменения подготавливаются для фиксации.
Local Repository: Локальный репозиторий, где хранятся зафиксированные изменения.
Remote Repository: Удалённый репозиторий, например, на платформах GitLab, GitHub или Bitbucket.
В нижней части схемы представлена последовательность действий при выполнении команды git pull.
Эта схема полезна для понимания основных этапов работы с Git.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🍾2
Сравнение, которое снова разожгло споры о лаконичности языков программирования.
На скриншоте один и тот же HTTP-сервер с маршрутом
Вариант на C# использует минимальный API из ASP.NET Core и укладывается в несколько строк.
Реализация на Clojure выглядит заметно объёмнее: отдельное описание обработчика, заголовков ответа и запуск Jetty-сервера.
👉 @KodBlog
На скриншоте один и тот же HTTP-сервер с маршрутом
"/" и ответом "Hello world" реализован на Clojure и C#.Вариант на C# использует минимальный API из ASP.NET Core и укладывается в несколько строк.
Реализация на Clojure выглядит заметно объёмнее: отдельное описание обработчика, заголовков ответа и запуск Jetty-сервера.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🍾4
Большинство разработчиков изучают PostgreSQL в неправильном порядке.
Вот мой личный план изучения, разделённый на 7 уровней.
Не начинайте сразу с:
* тюнинга производительности
* индексов
* репликации
* партиционирования
Чтобы действительно хорошо разбираться в PostgreSQL, нужно понимать, за что отвечает каждый уровень.
1️⃣ Основы SQL
Прежде чем думать об индексах, производительности или масштабировании, нужно уверенно владеть базовым языком работы с базами данных:
* SELECT
* WHERE
* ORDER BY
* GROUP BY
* агрегатные функции
* базовые JOIN'ы
* LIMIT и OFFSET
* DISTINCT
Слабое знание SQL обычно приводит к неаккуратным запросам, лишней сложности и проблемам с производительностью в будущем.
2️⃣ Моделирование данных
Когда вы уже умеете писать запросы, следующий шаг — научиться правильно структурировать данные.
Сюда входят:
* таблицы
* схемы
* первичные ключи
* внешние ключи
* ограничения
* связи
* нормализация
* типы данных
* соглашения по именованию
Прежде чем оптимизировать базу данных, нужно её правильно спроектировать.
3️⃣ Продвинутые запросы
На этом этапе вы переходите от простых запросов к более выразительным SQL-конструкциям:
* JOIN'ы
* подзапросы
* CTE
* оконные функции
* условные выражения
* продвинутые агрегации
* запросы к JSON и JSONB
* операции с массивами
Этот уровень позволяет решать сложные бизнес-задачи непосредственно внутри базы данных.
4️⃣ Индексы
Сначала вас волнует, работает ли запрос вообще.
Потом начинает волновать, работает ли он быстро.
Здесь в игру вступают индексы.
Нужно понимать:
* индексы B-tree
* индексы GIN
* индексы GiST
* частичные индексы
* составные индексы
* уникальные индексы
* обслуживание индексов
* когда индексы помогают
* когда индексы вредят
Цель не в том, чтобы добавлять индексы везде подряд.
Цель — понимать, как ваше приложение читает данные.
5️⃣ Тюнинг производительности
На этом уровне вы учитесь анализировать, что база данных делает на самом деле.
Важные темы:
* EXPLAIN
* EXPLAIN ANALYZE
* планирование запросов
* анализ использования индексов
* VACUUM
* ANALYZE
* раздувание таблиц (table bloat)
* статистика
* логи медленных запросов
* настройки памяти и I/O
* настройка конфигурации
Тюнинг производительности — это не угадывание.
Это расследование.
6️⃣ Администрирование
PostgreSQL в продакшене — это не только написание запросов.
Её также нужно безопасно и надёжно эксплуатировать.
Этот уровень включает:
* роли и права доступа
* резервное копирование и восстановление
* репликацию
* мониторинг и оповещения
* пулинг соединений
* настройку безопасности
* миграции и обновления
* процессы обслуживания
* планирование аварийного восстановления
7️⃣ Масштабирование и экосистема
Масштабирование — это верхний уровень, а не отправная точка.
Сюда входят:
* партиционирование
* реплики для чтения
* высокая доступность
* логическая репликация
* шаблоны шардирования
* управляемые сервисы PostgreSQL
* инструменты наблюдаемости
* интеграции с экосистемой
* расширения вроде PostGIS, pg_trgm и TimescaleDB
Прочный фундамент — ключ к изучению чего угодно.
👉 @KodBlog
Вот мой личный план изучения, разделённый на 7 уровней.
Не начинайте сразу с:
* тюнинга производительности
* индексов
* репликации
* партиционирования
Чтобы действительно хорошо разбираться в PostgreSQL, нужно понимать, за что отвечает каждый уровень.
1️⃣ Основы SQL
Прежде чем думать об индексах, производительности или масштабировании, нужно уверенно владеть базовым языком работы с базами данных:
* SELECT
* WHERE
* ORDER BY
* GROUP BY
* агрегатные функции
* базовые JOIN'ы
* LIMIT и OFFSET
* DISTINCT
Слабое знание SQL обычно приводит к неаккуратным запросам, лишней сложности и проблемам с производительностью в будущем.
2️⃣ Моделирование данных
Когда вы уже умеете писать запросы, следующий шаг — научиться правильно структурировать данные.
Сюда входят:
* таблицы
* схемы
* первичные ключи
* внешние ключи
* ограничения
* связи
* нормализация
* типы данных
* соглашения по именованию
Прежде чем оптимизировать базу данных, нужно её правильно спроектировать.
3️⃣ Продвинутые запросы
На этом этапе вы переходите от простых запросов к более выразительным SQL-конструкциям:
* JOIN'ы
* подзапросы
* CTE
* оконные функции
* условные выражения
* продвинутые агрегации
* запросы к JSON и JSONB
* операции с массивами
Этот уровень позволяет решать сложные бизнес-задачи непосредственно внутри базы данных.
4️⃣ Индексы
Сначала вас волнует, работает ли запрос вообще.
Потом начинает волновать, работает ли он быстро.
Здесь в игру вступают индексы.
Нужно понимать:
* индексы B-tree
* индексы GIN
* индексы GiST
* частичные индексы
* составные индексы
* уникальные индексы
* обслуживание индексов
* когда индексы помогают
* когда индексы вредят
Цель не в том, чтобы добавлять индексы везде подряд.
Цель — понимать, как ваше приложение читает данные.
5️⃣ Тюнинг производительности
На этом уровне вы учитесь анализировать, что база данных делает на самом деле.
Важные темы:
* EXPLAIN
* EXPLAIN ANALYZE
* планирование запросов
* анализ использования индексов
* VACUUM
* ANALYZE
* раздувание таблиц (table bloat)
* статистика
* логи медленных запросов
* настройки памяти и I/O
* настройка конфигурации
Тюнинг производительности — это не угадывание.
Это расследование.
6️⃣ Администрирование
PostgreSQL в продакшене — это не только написание запросов.
Её также нужно безопасно и надёжно эксплуатировать.
Этот уровень включает:
* роли и права доступа
* резервное копирование и восстановление
* репликацию
* мониторинг и оповещения
* пулинг соединений
* настройку безопасности
* миграции и обновления
* процессы обслуживания
* планирование аварийного восстановления
7️⃣ Масштабирование и экосистема
Масштабирование — это верхний уровень, а не отправная точка.
Сюда входят:
* партиционирование
* реплики для чтения
* высокая доступность
* логическая репликация
* шаблоны шардирования
* управляемые сервисы PostgreSQL
* инструменты наблюдаемости
* интеграции с экосистемой
* расширения вроде PostGIS, pg_trgm и TimescaleDB
Прочный фундамент — ключ к изучению чего угодно.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤3🍾2
Воскресенский совет для .NET-разработчиков: перестаньте использовать
Используйте
Тогда приложение будет работать с реальными часами, а в тестах вы сможете подставлять фейковые часы и вручную двигать время вперёд.
Небольшая абстракция — зато тесты становятся гораздо удобнее.
На примере:
В тесте:
Никаких задержек, никаких сюрпризов от
https://learn.microsoft.com/ru-ru/dotnet/standard/datetime/timeprovider-overview
👉 @KodBlog
DateTime.UtcNow напрямую в коде.Используйте
TimeProvider.Тогда приложение будет работать с реальными часами, а в тестах вы сможете подставлять фейковые часы и вручную двигать время вперёд.
Небольшая абстракция — зато тесты становятся гораздо удобнее.
На примере:
public sealed class TrialService(TimeProvider clock)
{
public bool IsExpired(DateTimeOffset startedAt) =>
clock.GetUtcNow() >= startedAt.AddDays(14);
}
В тесте:
var clock = new FakeTimeProvider(startedAt);
var service = new TrialService(clock);
clock.Advance(TimeSpan.FromDays(15));
Assert.True(service.IsExpired(startedAt));
Никаких задержек, никаких сюрпризов от
DateTime.UtcNow. Просто перематываете время вперёд в тестах и проверяете нужный сценарий.https://learn.microsoft.com/ru-ru/dotnet/standard/datetime/timeprovider-overview
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🍾2🔥1
Нашёл интересный инструмент для поиска и устранения дублирующегося кода.
Называется Deslop. Написан на Rust, но работает не только с Rust-проектами — поддерживает Python, Dart и C#.
Инструмент анализирует кодовую базу, находит дубликаты и помогает избавиться от повторяющихся фрагментов. Автор предлагает просто установить его в VS Code или любой другой форк редактора и использовать прямо в процессе разработки.
Автор проекта также собрал отдельную подборку статей и исследований, которые легли в основу алгоритмов Deslop.
Если в проекте много копипасты и похожих реализаций, инструмент может помочь быстро найти кандидатов на рефакторинг.
👉 @KodBlog
Называется Deslop. Написан на Rust, но работает не только с Rust-проектами — поддерживает Python, Dart и C#.
Инструмент анализирует кодовую базу, находит дубликаты и помогает избавиться от повторяющихся фрагментов. Автор предлагает просто установить его в VS Code или любой другой форк редактора и использовать прямо в процессе разработки.
Автор проекта также собрал отдельную подборку статей и исследований, которые легли в основу алгоритмов Deslop.
Если в проекте много копипасты и похожих реализаций, инструмент может помочь быстро найти кандидатов на рефакторинг.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🍾1
🚀 В .NET 11 Preview 6 появилась новая возможность из C# 15 — extension indexers.
Теперь индексаторы можно объявлять прямо внутри extension-блоков:
Это позволяет добавлять индексаторы к существующим типам без изменения их исходного кода, так же как сегодня работают extension methods.
Фича уже влита в C# 15 Preview и доступна в .NET 11 Preview 6.🔥
https://github.com/dotnet/csharplang/blob/main/proposals/extension-indexers.md
👉 @KodBlog
Теперь индексаторы можно объявлять прямо внутри extension-блоков:
static class E
{
extension(...)
{
int this[...] { get => ...; set => ...; }
}
}
Это позволяет добавлять индексаторы к существующим типам без изменения их исходного кода, так же как сегодня работают extension methods.
Фича уже влита в C# 15 Preview и доступна в .NET 11 Preview 6.
https://github.com/dotnet/csharplang/blob/main/proposals/extension-indexers.md
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
csharplang/proposals/extension-indexers.md at main · dotnet/csharplang
The official repo for the design of the C# programming language - dotnet/csharplang
👍7👎4🔥1🍾1
Docker-ошибка, которую я вижу почти в каждом junior Dockerfile:
должно быть:
почему это важно?
docker кэширует каждую инструкцию как отдельный слой
исходный код меняется с каждым коммитом
поэтому
если поменять порядок, слой с установкой зависимостей остаётся в кэше даже при изменении кода, потому что он зависит только от
одна перестановка строк. экономит 40+ секунд на каждой пересборке. кэшируй зависимости, а не код.
👉 @KodBlog
COPY . .
RUN npm install
должно быть:
COPY package*.json ./
RUN npm install
COPY . .
почему это важно?
docker кэширует каждую инструкцию как отдельный слой
исходный код меняется с каждым коммитом
поэтому
COPY . . ломает кэш, и всё после него (включая npm install) пересобирается с нуля при каждой сборкеесли поменять порядок, слой с установкой зависимостей остаётся в кэше даже при изменении кода, потому что он зависит только от
package.jsonодна перестановка строк. экономит 40+ секунд на каждой пересборке. кэшируй зависимости, а не код.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤5🍾1