День триста тридцать первый. #AsyncAwaitFAQ
FAQ по async/await и ConfigureAwait
7. Нужно ли использовать ConfigureAwait(false) при вызове GetAwaiter().GetResult()?
Нет.
Говорят, что ConfigureAwait(false) больше не требуется в .NET Core. Это правда?
Нет. Он необходим при работе в .NET Core по тем же причинам, что и при работе в .NET Framework. В этом отношении ничего не изменилось.
Однако изменилось поведение некоторых сред в части публикации собственного контекста. Например, если ASP.NET в .NET Framework имеет свой собственный
Но это не означает, что пользовательский
Можно ли использовать ConfigureAwait в await foreach для IAsyncEnumerable?
Да.
Можно ли использовать ConfigureAwait в await using для IAsyncDisposable?
Да, хотя есть небольшой нюанс. Как и в случае
Источник: https://devblogs.microsoft.com/dotnet/configureawait-faq/
FAQ по async/await и ConfigureAwait
7. Нужно ли использовать ConfigureAwait(false) при вызове GetAwaiter().GetResult()?
Нет.
ConfigureAwait
влияет только на обратные вызовы. В частности, паттерн awaiter требует, чтобы ожидатели предоставили свойство IsCompleted
, метод GetResult
и метод OnCompleted
. ConfigureAwait влияет только на поведение OnCompleted
, поэтому, если вы просто напрямую вызываете метод GetResult()
разницы в поведении не будет. Поэтому можно заменитьtask.ConfigureAwait(false).GetAwaiter().GetResult();на
task.GetAwaiter().GetResult();если, конечно, вы действительно хотите блокировать текущий поток.
Говорят, что ConfigureAwait(false) больше не требуется в .NET Core. Это правда?
Нет. Он необходим при работе в .NET Core по тем же причинам, что и при работе в .NET Framework. В этом отношении ничего не изменилось.
Однако изменилось поведение некоторых сред в части публикации собственного контекста. Например, если ASP.NET в .NET Framework имеет свой собственный
SynchronizationContext
, то в ASP.NET Core нет. Это означает, что код, работающий в приложении ASP.NET Core по умолчанию, не увидит пользовательский SynchronizationContext
, что исключает необходимость вызова ConfigureAwait(false)
в такой среде.Но это не означает, что пользовательский
SynchronizationContext
или TaskScheduler
никогда не будут предоставлены. Если какой-либо пользовательский код (или код библиотеки), используемый вашим приложением, задаёт пользовательский контекст, то даже в ASP.NET Core ваши вызовы await могут захватывать контекст или планировщик, что может повлечь необходимость использования ConfigureAwait(false)
.Можно ли использовать ConfigureAwait в await foreach для IAsyncEnumerable?
Да.
await foreach
работает с шаблоном, поэтому он может использоваться для перечисления не только IAsyncEnumerable<T>
, но и всего, что соответствует шаблону. Библиотеки .NET Runtime включают метод расширения ConfigureAwait
для IAsyncEnumerable<T>
, который возвращает сконфигурированную структуру, соответствующую шаблону. Когда компилятор генерирует вызовы методов MoveNextAsync
и DisposeAsync
перечислителя, структура выполняет ожидание желаемым способом.Можно ли использовать ConfigureAwait в await using для IAsyncDisposable?
Да, хотя есть небольшой нюанс. Как и в случае
IAsyncEnumerable<T>
, библиотеки .NET Runtime предоставляют метод расширения ConfigureAwait
для IAsyncDisposable
. И await using
будет успешно работать с ним, поскольку он реализует соответствующий шаблон (предоставляет метод DisposeAsync
):await using (var c = new MyAsyncDisposableClass().ConfigureAwait(false)) {…}Проблема здесь в том, что тип c теперь не
MyAsyncDisposableClass
, а System.Runtime.CompilerServices.ConfiguredAsyncDisposable
, возвращаемый из метода расширения ConfigureAwait
. Чтобы обойти это, вам нужно написать одну дополнительную строку:var c = new MyAsyncDisposableClass();Это расширяет область действия
await using (c.ConfigureAwait(false)){…}
c
, и, если это критично, можно обернуть всё это в фигурные скобки.Источник: https://devblogs.microsoft.com/dotnet/configureawait-faq/
День триста тридцать второй. #ЗадачиНаСобеседовании
Встречаю много вопросов на тему, чего ждать на собеседовании, к чему готовиться, что нужно знать и т.п. Поскольку лично я работаю в одной компании уже 12 лет, то считать себя экспертом по собесам не могу. Поэтому лучше сошлюсь на хорошее видео на эту тему от АйТиБороды.
А в этом посте хотел бы привести одну из практических задач. Не знаю, как у нас, а на собеседованиях в заграничных «ИТ-гигантах» умение решать задачи ценится больше, чем просто знание технологий. Возможно, это и правильно. Как я упоминал ранее, я нашёл канал одного парня, его зовут Клемент Михалеску, который занимается интервью кандидатов в Гугле. Так вот, в одном видео (не спешите смотреть, чтобы не заспойлерить) мне понравилась задача, которую предлагают решить кандидату на собеседовании.
Дана коллекция точек на плоскости с координатами (x, y). См. рисунок ниже (он немного кривоват, но суть, думаю, понятна). Для простоты допустим, что все координаты целочисленные. Нужно написать функцию, которая будет вычислять количество прямоугольников, образованных этими точками. Очевидные правила:
- прямоугольник должен иметь 4 точки в углах,
- ненулевые длину и ширину,
- прямоугольники, образованные четырьмя одинаковыми точками A,B,E,D (см. рисунок) считаются как один (то есть ABED = BEDA = EDBA и т.п. – все считать за 1).
Итак, что мне понравилось в описании процесса интервью.
Во-первых, интервью длится около часа, и никто не ждёт от вас, что вы тут же напишете идеально правильный, компилирующийся и работающий код. Тем более, что на интервью даётся листок бумаги (документ Google Docs в видео), а не IDE. Интервьюеру интересен ход ваших мыслей. То есть вам даётся задание, вы начинаете рассуждать вслух, возможно записывать какой-то псевдокод. Хороший интервьюер (как в видео) будет рассуждать вместе с вами и задавать наводящие вопросы или корректировать, если вы полезете не в ту степь. Точно так же, как впоследствии вы будете работать и решать задачи в команде.
Во-вторых, сначала вам дают упрощённый вариант задачи. В данном случае допустим, что нужно посчитать прямоугольники, стороны которых параллельны осям координат. То есть пока мы не будем считать прямоугольник BDHF. Кстати, в видео «кандидат» блестяще с этим справляется, можете посмотреть решение до 20й минуты.
Кроме собственно решения интервьюер попросил пройти его по шагам, чтобы убедиться в правильности и понять ход мыслей самому, а также оценить «стоимость» решения как по времени, так и по занимаемой памяти. Вот это тоже нужно уметь делать.
Ну а дальше, если интервьюер действительно хочет оценить силу кандидата, то даст ему попробовать решить и усложнённый вариант. Собственно, Клемент поясняет далее во врезке, что от кандидата не ждут, что он сразу, прямо во время интервью, решит усложнённый вариант (чаще всего это не реально). Интервьюеру интереснее посмотреть на мыслительный процесс кандидата и то, как он справляется с действительно сложными задачами.
Интересно, что я практически уверен, что решение упрощённого варианта в видео правильное, а вот до решения усложнённого варианта, как мне показалось, они так и не дошли.
Итак, теперь нам нужно посчитать все возможные прямоугольники.
У меня есть теория решения, в которой я более-менее уверен, но пока не проверял. Приглашаю всех предлагать варианты решения в чате.
Встречаю много вопросов на тему, чего ждать на собеседовании, к чему готовиться, что нужно знать и т.п. Поскольку лично я работаю в одной компании уже 12 лет, то считать себя экспертом по собесам не могу. Поэтому лучше сошлюсь на хорошее видео на эту тему от АйТиБороды.
А в этом посте хотел бы привести одну из практических задач. Не знаю, как у нас, а на собеседованиях в заграничных «ИТ-гигантах» умение решать задачи ценится больше, чем просто знание технологий. Возможно, это и правильно. Как я упоминал ранее, я нашёл канал одного парня, его зовут Клемент Михалеску, который занимается интервью кандидатов в Гугле. Так вот, в одном видео (не спешите смотреть, чтобы не заспойлерить) мне понравилась задача, которую предлагают решить кандидату на собеседовании.
Дана коллекция точек на плоскости с координатами (x, y). См. рисунок ниже (он немного кривоват, но суть, думаю, понятна). Для простоты допустим, что все координаты целочисленные. Нужно написать функцию, которая будет вычислять количество прямоугольников, образованных этими точками. Очевидные правила:
- прямоугольник должен иметь 4 точки в углах,
- ненулевые длину и ширину,
- прямоугольники, образованные четырьмя одинаковыми точками A,B,E,D (см. рисунок) считаются как один (то есть ABED = BEDA = EDBA и т.п. – все считать за 1).
Итак, что мне понравилось в описании процесса интервью.
Во-первых, интервью длится около часа, и никто не ждёт от вас, что вы тут же напишете идеально правильный, компилирующийся и работающий код. Тем более, что на интервью даётся листок бумаги (документ Google Docs в видео), а не IDE. Интервьюеру интересен ход ваших мыслей. То есть вам даётся задание, вы начинаете рассуждать вслух, возможно записывать какой-то псевдокод. Хороший интервьюер (как в видео) будет рассуждать вместе с вами и задавать наводящие вопросы или корректировать, если вы полезете не в ту степь. Точно так же, как впоследствии вы будете работать и решать задачи в команде.
Во-вторых, сначала вам дают упрощённый вариант задачи. В данном случае допустим, что нужно посчитать прямоугольники, стороны которых параллельны осям координат. То есть пока мы не будем считать прямоугольник BDHF. Кстати, в видео «кандидат» блестяще с этим справляется, можете посмотреть решение до 20й минуты.
Кроме собственно решения интервьюер попросил пройти его по шагам, чтобы убедиться в правильности и понять ход мыслей самому, а также оценить «стоимость» решения как по времени, так и по занимаемой памяти. Вот это тоже нужно уметь делать.
Ну а дальше, если интервьюер действительно хочет оценить силу кандидата, то даст ему попробовать решить и усложнённый вариант. Собственно, Клемент поясняет далее во врезке, что от кандидата не ждут, что он сразу, прямо во время интервью, решит усложнённый вариант (чаще всего это не реально). Интервьюеру интереснее посмотреть на мыслительный процесс кандидата и то, как он справляется с действительно сложными задачами.
Интересно, что я практически уверен, что решение упрощённого варианта в видео правильное, а вот до решения усложнённого варианта, как мне показалось, они так и не дошли.
Итак, теперь нам нужно посчитать все возможные прямоугольники.
У меня есть теория решения, в которой я более-менее уверен, но пока не проверял. Приглашаю всех предлагать варианты решения в чате.
👍1
Интересны ли вам подобные задачи на канале?
Anonymous Poll
43%
Да
48%
Да, делать пост с объяснением решения позже
9%
Нет
День триста тридцать третий. #DesignPatterns
Паттерны проектирования
5. Паттерн «Наблюдатель» (Observer)
Существует два способа общения между двумя программными элементами.
Назначение: определяет зависимость типа «один ко многим» между объектами таким образом, что при изменении состояния одного объекта все зависящие от него оповещаются об этом и автоматически обновляются.
Причины использования:
При проектировании некоторого класса у разработчика всегда есть несколько вариантов реализации. Класс
Классическая диаграмма приведена на рисунке ниже:
-
-
-
-
На платформе .NET практически невозможно встретить классическую реализацию паттерна «Наблюдатель». Существует несколько вариантов реализации:
1. С помощью делегатов (методов обратного вызова).
Самая простая форма наблюдателя. Для этого достаточно, чтобы класс потребовал делегат в аргументах конструктора и уведомлял вызывающий код с его помощью. Это позволяет гарантировать наличие наблюдателя, а также наблюдаемый объект может не только уведомлять об изменении своего состояния, но и требовать от делегата некоторого результата.
2. С помощью событий (events).
События представляют собой умную оболочку над делегатами, которая позволяет клиентам лишь подписываться на события или отказываться от подписки, а владельцу события — инициировать событие для уведомления всех подписчиков. Разница с первым вариантом в том, что интерфейс наблюдаемого объекта позволяет подписаться на событие любому числу подписчиков. При этом нет гарантии, что эти подписчики вообще будут. Подробнее о событиях
3. С помощью специализированных интерфейсов-наблюдателей.
В некоторых случаях, когда имеется несколько событий или делегатов, их удобно объединить в одном интерфейсе. Данный вариант очень похож на классическую версию паттерна «Наблюдатель», хотя обычно наблюдатель является единственным.
4. С помощью интерфейсов IObserver/IObservable.
Все перечисленные ранее варианты реализации паттерна «Наблюдатель» содержат одно ограничение: они плохо объединяются для получения более высокоуровневого поведения (not composable). Над событиями или делегатами невозможно выполнять операции, которые можно выполнять над последовательностями. С 4-й версии в .NET Framework появилась пара интерфейсов
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 5.
Паттерны проектирования
5. Паттерн «Наблюдатель» (Observer)
Существует два способа общения между двумя программными элементами.
Компонент 1
может обратиться к Компоненту 2
для получения каких-то данных или выполнения некоторой операции, либо Компонент 2
может уведомить Компонент 1
о некотором событии. Первая модель взаимодействия называется pull-моделью, а вторая — push-моделью. В мире ООП push-модель реализуется с помощью паттерна «Наблюдатель».Назначение: определяет зависимость типа «один ко многим» между объектами таким образом, что при изменении состояния одного объекта все зависящие от него оповещаются об этом и автоматически обновляются.
Причины использования:
При проектировании некоторого класса у разработчика всегда есть несколько вариантов реализации. Класс
А
может знать о существовании класса Б
и уведомлять его о произошедшем событии. Или же класс А
может быть наблюдаемым и уведомлять о некотором событии всех заинтересованных подписчиков. Использование наблюдателей уменьшает связанность между классами/модулями и упрощает повторное использование. Благодаря слабой связанности наблюдаемый объект и наблюдатели могут располагаться на разных уровнях абстракции или слоях приложения. Например, слой пользовательского интерфейса знает о модели, но модель не должна ничего знать о пользовательском интерфейсе.Классическая диаграмма приведена на рисунке ниже:
-
Observer
— определяет интерфейс наблюдателя;-
Subject
(наблюдаемый объект) — определяет методы подключения и отключения наблюдателей;-
ConcreteObserver
— реализует интерфейс наблюдателя;-
ConcreteSubject
— конкретный тип наблюдаемого объекта.На платформе .NET практически невозможно встретить классическую реализацию паттерна «Наблюдатель». Существует несколько вариантов реализации:
1. С помощью делегатов (методов обратного вызова).
Самая простая форма наблюдателя. Для этого достаточно, чтобы класс потребовал делегат в аргументах конструктора и уведомлял вызывающий код с его помощью. Это позволяет гарантировать наличие наблюдателя, а также наблюдаемый объект может не только уведомлять об изменении своего состояния, но и требовать от делегата некоторого результата.
2. С помощью событий (events).
События представляют собой умную оболочку над делегатами, которая позволяет клиентам лишь подписываться на события или отказываться от подписки, а владельцу события — инициировать событие для уведомления всех подписчиков. Разница с первым вариантом в том, что интерфейс наблюдаемого объекта позволяет подписаться на событие любому числу подписчиков. При этом нет гарантии, что эти подписчики вообще будут. Подробнее о событиях
3. С помощью специализированных интерфейсов-наблюдателей.
В некоторых случаях, когда имеется несколько событий или делегатов, их удобно объединить в одном интерфейсе. Данный вариант очень похож на классическую версию паттерна «Наблюдатель», хотя обычно наблюдатель является единственным.
4. С помощью интерфейсов IObserver/IObservable.
Все перечисленные ранее варианты реализации паттерна «Наблюдатель» содержат одно ограничение: они плохо объединяются для получения более высокоуровневого поведения (not composable). Над событиями или делегатами невозможно выполнять операции, которые можно выполнять над последовательностями. С 4-й версии в .NET Framework появилась пара интерфейсов
IObserver
/IObservable
с набором методов расширений, известных под названием реактивных расширений (Rx, Reactive Extensions). Интерфейс IObservable
моделирует реактивные последовательности и позволяет работать с наблюдаемыми последовательностями через привычный LINQ-синтаксис. Он предполагает, что однородные события будут периодически повторяться. Наблюдаемый объект может уведомить о новом событии (OnNext
), о том, что в процессе события произошла ошибка (OnError
), или о том, что цепочка событий завершена (OnComplete
). Пример: поток сетевых сообщений от клиента или сервера, координаты устройства и т.п.Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 5.
День триста тридцать четвёртый. #ЗадачиНаСобеседовании
Ответ на задачу
Дана коллекция точек на плоскости с координатами (x, y). Для простоты допустим, что все координаты целочисленные. Нужно написать функцию, которая будет вычислять количество прямоугольников, которые образуют эти точки.
Как я уже говорил, у меня есть теория решения, в которой я более-менее уверен, но пока не проверял.
Итак, пусть у нас есть коллекция точек Point { int x; int y; }. Мы проходим по коллекции и для каждой точки добавляем в коллекцию вектор, начинающийся в этой точке и заканчивающийся в любой точке, которая выше этой точки (координата y больше координаты y текущей точки – y2 > y1), либо на том же уровне по высоте, но правее (x2 > x1, если y2 = y1). Таким образом для точки A (см. рисунок ниже) мы добавляем векторы AB, AC, AD, но не добавляем вектор AE (он будет учтён для точки E, как EA). Кроме того, для каждого вектора мы считаем его «направление» (x2 – x1, y2 – y1). Например, для точек A(0,0) и B(-1,4), направление вектора AB = (-1,4), а для AD = (11,7).
Таким образом получим коллекцию векторов
double
Таким образом считаем количество для всех векторов и делим общее количество на 2, поскольку мы посчитаем прямоугольник ABCD дважды для векторов AB и AC).
По поводу стоимости: если у нас N точек, тогда в худшем случае у будет N(N-1)/2 векторов, то есть O(N^2) времени на создание векторов и O(N^4) на обход.
Как-то так. Если у вас есть вопросы или замечания, добро пожаловать в чат.
Ответ на задачу
Дана коллекция точек на плоскости с координатами (x, y). Для простоты допустим, что все координаты целочисленные. Нужно написать функцию, которая будет вычислять количество прямоугольников, которые образуют эти точки.
Как я уже говорил, у меня есть теория решения, в которой я более-менее уверен, но пока не проверял.
Итак, пусть у нас есть коллекция точек Point { int x; int y; }. Мы проходим по коллекции и для каждой точки добавляем в коллекцию вектор, начинающийся в этой точке и заканчивающийся в любой точке, которая выше этой точки (координата y больше координаты y текущей точки – y2 > y1), либо на том же уровне по высоте, но правее (x2 > x1, если y2 = y1). Таким образом для точки A (см. рисунок ниже) мы добавляем векторы AB, AC, AD, но не добавляем вектор AE (он будет учтён для точки E, как EA). Кроме того, для каждого вектора мы считаем его «направление» (x2 – x1, y2 – y1). Например, для точек A(0,0) и B(-1,4), направление вектора AB = (-1,4), а для AD = (11,7).
Таким образом получим коллекцию векторов
struct Vector
{
Point A { get; set; }
Point B { get; set; }
(int x, int y) Direction
{
get
{
return (B.X - A.X, B.Y - A.Y);
}
}
}
Теперь для каждого вектора из набора ищем вектор с равным ему направлением и начальной точкой, выбранной по тому же правилу (выше начальной точки текущего вектора или на том же уровне, но правее). Например, для вектора AB таким будет вектор CD (но для вектора CD мы не найдём вектора AB, т.к. A ниже C). Мы получили две параллельные и равные стороны (поскольку направления равны). Остался ещё один момент. У прямоугольников есть свойство, что их диагонали равны. Поэтому сравниваем длины диагоналей (не используем квадратный корень из формулы расстояния, чтобы не заморачиваться с округлением):double
AD = Math.Pow(vCD.A.X - vAB.B.X, 2) + Math.Pow(vCD.A.Y - vAB.B.Y, 2);
double BC = Math.Pow(vAB.B.X - vCD.A.X, 2) + Math.Pow(vAB.B.Y - vCD.A.Y, 2);
Если диагонали AD и BC равны, у нас есть прямоугольник.Таким образом считаем количество для всех векторов и делим общее количество на 2, поскольку мы посчитаем прямоугольник ABCD дважды для векторов AB и AC).
По поводу стоимости: если у нас N точек, тогда в худшем случае у будет N(N-1)/2 векторов, то есть O(N^2) времени на создание векторов и O(N^4) на обход.
Как-то так. Если у вас есть вопросы или замечания, добро пожаловать в чат.
День триста тридцать пятый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
16. Замечание о комментариях.
На первом моём занятии по программированию в колледже преподаватель выдал по два бланка кода на Basic, написал на доске: «Напишите программу, принимающую результаты 10 игр в боулинг и рассчитывающую средний результат», - и вышел из класса. Насколько сложно это может быть? Я не помню свое окончательное решение, но я уверен, что в нем был цикл FOR/NEXT, и весь код был не длиннее 15 строк. Каждый бланк кода - да, дети, мы обычно писали код от руки перед тем, как вводить его в компьютер, - содержал около 70 строк. Мне было непонятно, почему преподаватель дал нам два бланка. Поскольку мой почерк всегда был корявым, я использовал второй бланк, чтобы аккуратно переписать свой код, надеясь получить пару дополнительных баллов.
К моему большому удивлению, когда я получил результат в начале следующего занятия, у меня была едва проходная оценка. (Это мучало меня потом всё время обучения в колледже.) Поперёк всего моего аккуратно переписанного кода было написано: «Без комментариев?»
Недостаточно того, чтобы мы с преподавателем знали, что должна делать программа. Частью задания было научить меня, что мой код должен быть понятен следующему программисту. Этот урок я не забыл.
Комментарии - не зло. Они так же необходимы в программировании, как основные конструкции кода. У большинства современных языков есть инструмент, анализирующий правильно отформатированные комментарии, чтобы автоматически генерировать документацию. Это очень хорошее начало, но этого недостаточно. Внутри вашего кода должны быть пояснения о том, что код должен делать. Кодирование по старому принципу: «Если было трудно писать, это должно быть трудно читать», - оказывает медвежью услугу вашему клиенту, вашему работодателю, вашим коллегам и в конечном итоге вам же в будущем.
С другой стороны, вы можете зайти слишком далеко в комментировании. Убедитесь, что ваши комментарии уточняют код, но не загромождают его. Добавляйте в код комментарии, объясняющие, что он должен выполнить. Заогловочные комментарии должны дать любому программисту достаточно информации, чтобы использовать ваш код без необходимости его чтения, в то время как встроенные комментарии должны помочь следующему разработчику исправить или улучшить его.
Однажды на работе я не согласился с проектом решения, принятым теми, кто был выше меня. Желая отомстить, как часто делают молодые программисты, я вставил текст письма, в котором указывалось, что нужно использовать их решение, в блок комментария в шапке файла. Оказалось, что менеджеры в этой компании перепроверяли код перед релизом. Так я познакомился со значением термина «действие, ограничивающее карьерный рост».
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Cal Evans
97 Вещей, Которые Должен Знать Каждый Программист
16. Замечание о комментариях.
На первом моём занятии по программированию в колледже преподаватель выдал по два бланка кода на Basic, написал на доске: «Напишите программу, принимающую результаты 10 игр в боулинг и рассчитывающую средний результат», - и вышел из класса. Насколько сложно это может быть? Я не помню свое окончательное решение, но я уверен, что в нем был цикл FOR/NEXT, и весь код был не длиннее 15 строк. Каждый бланк кода - да, дети, мы обычно писали код от руки перед тем, как вводить его в компьютер, - содержал около 70 строк. Мне было непонятно, почему преподаватель дал нам два бланка. Поскольку мой почерк всегда был корявым, я использовал второй бланк, чтобы аккуратно переписать свой код, надеясь получить пару дополнительных баллов.
К моему большому удивлению, когда я получил результат в начале следующего занятия, у меня была едва проходная оценка. (Это мучало меня потом всё время обучения в колледже.) Поперёк всего моего аккуратно переписанного кода было написано: «Без комментариев?»
Недостаточно того, чтобы мы с преподавателем знали, что должна делать программа. Частью задания было научить меня, что мой код должен быть понятен следующему программисту. Этот урок я не забыл.
Комментарии - не зло. Они так же необходимы в программировании, как основные конструкции кода. У большинства современных языков есть инструмент, анализирующий правильно отформатированные комментарии, чтобы автоматически генерировать документацию. Это очень хорошее начало, но этого недостаточно. Внутри вашего кода должны быть пояснения о том, что код должен делать. Кодирование по старому принципу: «Если было трудно писать, это должно быть трудно читать», - оказывает медвежью услугу вашему клиенту, вашему работодателю, вашим коллегам и в конечном итоге вам же в будущем.
С другой стороны, вы можете зайти слишком далеко в комментировании. Убедитесь, что ваши комментарии уточняют код, но не загромождают его. Добавляйте в код комментарии, объясняющие, что он должен выполнить. Заогловочные комментарии должны дать любому программисту достаточно информации, чтобы использовать ваш код без необходимости его чтения, в то время как встроенные комментарии должны помочь следующему разработчику исправить или улучшить его.
Однажды на работе я не согласился с проектом решения, принятым теми, кто был выше меня. Желая отомстить, как часто делают молодые программисты, я вставил текст письма, в котором указывалось, что нужно использовать их решение, в блок комментария в шапке файла. Оказалось, что менеджеры в этой компании перепроверяли код перед релизом. Так я познакомился со значением термина «действие, ограничивающее карьерный рост».
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Cal Evans
This media is not supported in your browser
VIEW IN TELEGRAM
День триста тридцать шестой.
С новым годом, дорогие читатели. Чистого вам кода без багов и ворнингов, зелёных тестов и шустрых IDE, адекватных заказчиков и блестящих идей для реализации их хотелок.
Много денег желать не буду, счастье не в них. Главное, чтобы их хватало на то, чтобы не волноваться об их недостатке, а получать удовольствие от работы. Ведь в этом настоящее счастье: заниматься любимым делом, приносить людям пользу. А если за это ещё и платят, так вообще жизнь удалась!
Счастья вам! С новым годом!
С новым годом, дорогие читатели. Чистого вам кода без багов и ворнингов, зелёных тестов и шустрых IDE, адекватных заказчиков и блестящих идей для реализации их хотелок.
Много денег желать не буду, счастье не в них. Главное, чтобы их хватало на то, чтобы не волноваться об их недостатке, а получать удовольствие от работы. Ведь в этом настоящее счастье: заниматься любимым делом, приносить людям пользу. А если за это ещё и платят, так вообще жизнь удалась!
Счастья вам! С новым годом!
День триста тридцать седьмой. #Оффтоп
Пока отходите от празднования нового года, вот вам пара ненапряжных интересных видео.
Обычно объяснение того, как выполняется ваш высокоуровневый код в .Net на компьютере заканчивается на этапе JIT-компиляции. Но что же происходит потом?
В первом видео рассказывается о том, как программа вычисления чисел Фибоначчи на C (не пугайтесь, синтаксис очень похож на C#) компилируется в машинный код: https://www.youtube.com/watch?v=yOyaJXpAYZQ
А во втором видео уже скомпилированный код переводится в настоящие нули и единицы команд и аргументов и передаётся в самодельный компьютер, на котором и запускается: https://www.youtube.com/watch?v=a73ZXDJtU48
Извините, как обычно, видео на английском, но, думаю, что даже базовых знаний будет достаточно. Объясняется довольно подробно.
Источник: https://www.youtube.com/user/eaterbc
Пока отходите от празднования нового года, вот вам пара ненапряжных интересных видео.
Обычно объяснение того, как выполняется ваш высокоуровневый код в .Net на компьютере заканчивается на этапе JIT-компиляции. Но что же происходит потом?
В первом видео рассказывается о том, как программа вычисления чисел Фибоначчи на C (не пугайтесь, синтаксис очень похож на C#) компилируется в машинный код: https://www.youtube.com/watch?v=yOyaJXpAYZQ
А во втором видео уже скомпилированный код переводится в настоящие нули и единицы команд и аргументов и передаётся в самодельный компьютер, на котором и запускается: https://www.youtube.com/watch?v=a73ZXDJtU48
Извините, как обычно, видео на английском, но, думаю, что даже базовых знаний будет достаточно. Объясняется довольно подробно.
Источник: https://www.youtube.com/user/eaterbc
День триста тридцать восьмой. #DesignPatterns
Паттерны проектирования
6. Паттерн «Посетитель» (Visitor). Начало
Назначение: описывает операцию, выполняемую с каждым объектом из некоторой иерархии классов. Паттерн «Посетитель» позволяет определить новую операцию, не изменяя классов этих объектов.
Причины использования:
Объектно-ориентированное программирование предполагает единство данных и операций. Обычно классы представляют некоторые операции, скрывая структуры данных, над которыми эти операции производятся. Но не всегда удобно или возможно смешивать операции и данные в одном месте. Логика операции может меняться независимо от самих данных, а вынесение такой логики за пределы иерархии данных чревато дублированием кода и хрупкостью.
В объектно-ориентированном решении базовый класс иерархии задаёт семейство операций, поведение которых определяется наследниками. Таким образом легко добавлять новый тип в иерархию, но сложно добавлять новую операцию (приходится изменять все типы в иерархии). Паттерн «Посетитель» позволяет решить эту проблему. Посетитель позволяет клиентскому коду исследовать иерархию типов и выполнять различные операции в зависимости от конкретного типа объекта.
При этом паттерн «Посетитель» усложняет добавление новых типов в иерархию наследования. Добавление нового типа требует изменения интерфейса посетителя и ломает все его реализации. Это значит, что паттерн «Посетитель» идеально подходит для расширения функциональности стабильных иерархий наследования с переменным числом операций.
Классическая диаграмма приведена на рисунке ниже:
-
-
-
В базовый класс
Интерфейс или абстрактный класс посетителя
Обычно посетитель Visitor определяется интерфейсом
Использование абстрактного базового класса
Функциональная версия
Когда количество конкретных типов иерархии наследования невелико, интерфейс посетителя можно заменить методом со списком делегатов. Для этого метод
- Использовать паттерн «Посетитель» нужно тогда, когда набор типов иерархии стабилен, а набор операций — нет.
- Классический вариант паттерна (с выделением интерфейса) лучше всего подходит для больших составных иерархий и когда заранее не известно, какие типы будут посещаться чаще других.
- Функциональный вариант посетителя всегда можно построить на основе классической реализации, когда станет известно, что многим клиентам нужно посещать лишь небольшое число типов иерархии.
Окончание следует...
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 6.
Паттерны проектирования
6. Паттерн «Посетитель» (Visitor). Начало
Назначение: описывает операцию, выполняемую с каждым объектом из некоторой иерархии классов. Паттерн «Посетитель» позволяет определить новую операцию, не изменяя классов этих объектов.
Причины использования:
Объектно-ориентированное программирование предполагает единство данных и операций. Обычно классы представляют некоторые операции, скрывая структуры данных, над которыми эти операции производятся. Но не всегда удобно или возможно смешивать операции и данные в одном месте. Логика операции может меняться независимо от самих данных, а вынесение такой логики за пределы иерархии данных чревато дублированием кода и хрупкостью.
В объектно-ориентированном решении базовый класс иерархии задаёт семейство операций, поведение которых определяется наследниками. Таким образом легко добавлять новый тип в иерархию, но сложно добавлять новую операцию (приходится изменять все типы в иерархии). Паттерн «Посетитель» позволяет решить эту проблему. Посетитель позволяет клиентскому коду исследовать иерархию типов и выполнять различные операции в зависимости от конкретного типа объекта.
При этом паттерн «Посетитель» усложняет добавление новых типов в иерархию наследования. Добавление нового типа требует изменения интерфейса посетителя и ломает все его реализации. Это значит, что паттерн «Посетитель» идеально подходит для расширения функциональности стабильных иерархий наследования с переменным числом операций.
Классическая диаграмма приведена на рисунке ниже:
-
Visitor
— определяет интерфейс посетителя;-
Element
— базовый класс иерархии, для которой нужно добавить новую операцию;-
Client
— использует посетитель для обработки иерархии элементов.В базовый класс
Element
добавляется абстрактный метод Accept
, который принимает Visitor
, а каждый конкретный класс иерархии просто вызывает метод Visit
переданного ему посетителя (в перегруженном методе Accept
).Интерфейс или абстрактный класс посетителя
Обычно посетитель Visitor определяется интерфейсом
IVisitor
. Такой подход налагает меньше ограничений на клиентов, но делает их более хрупкими. Каждый раз при добавлении типа в иерархию интерфейс посетителя обновляется и в нем появляется новый метод Visit(ConcreteElementC)
.Использование абстрактного базового класса
VisitorBase
позволяет клиентам посещать лишь нужные типы иерархии, переопределяя лишь нужные методы Visit
.Функциональная версия
Когда количество конкретных типов иерархии наследования невелико, интерфейс посетителя можно заменить методом со списком делегатов. Для этого метод
Accept
можно переименовать в Match
, который будет принимать несколько делегатов для обработки конкретных типов иерархии.public abstract class Element {Вызов:
public void Match(
Action<ConcreteElementA> handleA,
Action<ConcreteElementB> handleB)
{
switch (this) {
case ConcreteElementA element:
return handleA(element);
case ConcreteElementB element:
return handleB(element);
default:
throw new InvalidOperationException(…);
}
}
}
element.Match(a => HandleA(a), b => HandleB(b));Применение
- Использовать паттерн «Посетитель» нужно тогда, когда набор типов иерархии стабилен, а набор операций — нет.
- Классический вариант паттерна (с выделением интерфейса) лучше всего подходит для больших составных иерархий и когда заранее не известно, какие типы будут посещаться чаще других.
- Функциональный вариант посетителя всегда можно построить на основе классической реализации, когда станет известно, что многим клиентам нужно посещать лишь небольшое число типов иерархии.
Окончание следует...
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 6.
День триста тридцать девятый. #DesignPatterns
Паттерны проектирования
6. Паттерн «Посетитель» (Visitor). Окончание
Пример использования паттерна «Посетитель»
Каноническим примером демонстрации полиморфизма является иерархия фигур с базовым классом
Рассмотрим, как можно добавлять функциональность, используя паттерн «Посетитель».
1. Интерфейс посетителя:
- создать конкретный класс посетителя (
- создать и вызвать соответствующий метод расширения.
Понятно, что для такого простого примера единого метода расширения с сопоставлением по шаблону, вероятно, будет достаточно. Однако, если добавляемый функционал сложен и объёмен, реализация его в отдельном классе посетителя с разбиением на методы под каждый тип объекта будет предпочтительнее.
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 18.
Паттерны проектирования
6. Паттерн «Посетитель» (Visitor). Окончание
Пример использования паттерна «Посетитель»
Каноническим примером демонстрации полиморфизма является иерархия фигур с базовым классом
Shape
, имеющим абстрактный метод Area
(площадь фигуры), и несколькими потомками, например, Circle
, Rectangle
и Triangle
, каждый из которых переопределяет метод Area
. Допустим, что нам понадобилось добавить метод вычисления периметра фигуры. Ранее на канале приводился пример с использованием сопоставления по шаблону.Рассмотрим, как можно добавлять функциональность, используя паттерн «Посетитель».
1. Интерфейс посетителя:
public interface IShapeVisitor {2. Добавим в иерархию классов метод
void Visit(Circle circle);
void Visit(Triangle square);
void Visit(Rectangle rectangle);
}
Accept
, принимающий посетителя, и вызывающий в потомках метод Visit
посетителя:public abstract class Shape {3. Реализуем конкретного посетителя для вычисления периметра:
// … другие методы …
public abstract void Accept(IShapeVisitor visitor);
}
public class Circle : Shape {
// … другие методы …
public override void Accept(IShapeVisitor visitor)
=> visitor.Visit(this);
}
// … аналогично для других потомков
public class PerimeterVisitor : IShapeVisitor4. Создаём метод расширения:
{
public double Perimeter { get; private set; }
public void Visit(Circle circle) {
Perimeter = 2 * Math.PI * circle.Radius;
}
public void Visit(Rectangle rect) {
Perimeter = 2 * (rect.Height + rect.Width);
}
public void Visit(Triangle tri) {
Perimeter = tri.SideA + tri.SideB + tri.SideC;
}
}
public static class ShapeExtentions {Таким образом для любой новой функции (например, рисования фигуры) нам достаточно выполнить пункты 3 и 4:
public static double Perimeter(this Shape shape) {
var visitor = new PerimeterVisitor();
shape.Accept(visitor);
return visitor.Perimeter;
}
}
// Вызываем
Shape shape = … //получаем форму
var p = shape.Perimeter();
- создать конкретный класс посетителя (
DrawVisitor
);- создать и вызвать соответствующий метод расширения.
Понятно, что для такого простого примера единого метода расширения с сопоставлением по шаблону, вероятно, будет достаточно. Однако, если добавляемый функционал сложен и объёмен, реализация его в отдельном классе посетителя с разбиением на методы под каждый тип объекта будет предпочтительнее.
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 18.
День триста сороковой. #Оффтоп
Ещё одно ненапряжное видео. Абсолютно гениальный доклад Дилана Битти “The Art of Code” на конференции Build Stuff 2019. Философские рассуждения на тему, является ли программирование искусством. С кучей разнообразных примеров, красивой презентацией и тонким английским юмором. Я бы сказал, вот так нужно завлекать людей в программирование. Знаете, что такое квайн? Или что есть программа на языке Chef, которая в то же время является рецептом шоколадного пирога? А что изображено на картинке?
Располагайтесь поудобнее и насладитесь искусством программирования: https://youtu.be/gdSlcxxYAA8
Эээм… уже неловко об этом писать, конечно, но требуется хорошее знание английского.
Ещё одно ненапряжное видео. Абсолютно гениальный доклад Дилана Битти “The Art of Code” на конференции Build Stuff 2019. Философские рассуждения на тему, является ли программирование искусством. С кучей разнообразных примеров, красивой презентацией и тонким английским юмором. Я бы сказал, вот так нужно завлекать людей в программирование. Знаете, что такое квайн? Или что есть программа на языке Chef, которая в то же время является рецептом шоколадного пирога? А что изображено на картинке?
Располагайтесь поудобнее и насладитесь искусством программирования: https://youtu.be/gdSlcxxYAA8
Эээм… уже неловко об этом писать, конечно, но требуется хорошее знание английского.
День триста сорок первый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
17. Комментируйте только то, что код не может выразить
Разница между теорией и практикой гораздо очевиднее на практике, чем в теории – это как нельзя лучше относится к комментариям. Теоретически идея комментирования кода звучит убедительно: предложить читателю подробности, объяснение того, что происходит в коде. Что может быть полезнее, чем полезная добавка? Однако на практике комментарии часто становятся проблемой. Как и в любой другой форме письма, нужно уметь писать хорошие комментарии. В основном это умение заключается в том, чтобы знать, когда их не писать.
Когда код некорректен, компиляторы, интерпретаторы и другие инструменты обязательно найдут ошибку. Если код каким-либо образом некорректен в функциональном отношении, обзоры кода, статический анализ, тесты и повседневное использование в производственной среде устранят большинство ошибок. Но что насчет комментариев? В книге “The Elements of Programming Style” Керниган и Плаугер отмечают, что «комментарий имеет нулевую (или отрицательную) ценность, если он неправильный». И всё же такие комментарии часто засоряют код и остаются там даже дольше, чем ошибки. Они являются постоянной причиной отвлечения и источником дезинформации - маленьким, но препятствием в работе программиста.
Что можно сказать о комментариях, которые не являются технически неправильными, но не добавляют никакой ценности к коду? Такие комментарии являются шумом. Комментарии, которые повторяют код, не добавляют ничего полезного для читателя: сообщение о чём-либо один раз в коде и ещё раз на естественном языке не делает код более правильным или более красивым. Закомментированный код не выполняется, поэтому он не несёт никакой пользы ни для читателя, ни для среды исполнения. Такие комментарии также очень быстро устаревают. Комментарии, связанные с версией программы и закомментированный код пытаются рассказать о версиях и истории программы. На эти вопросы уже отвечают (гораздо более эффективно) инструменты контроля версий.
Большое количество бесполезных и неправильных комментариев в коде побуждает программистов игнорировать вообще все комментарии, либо пропуская их, либо принимая активные меры, чтобы их скрыть. Программисты находчивы и будут обходить всё, что воспринимается ими как помеха: скрывать комментарии, изменять цветовую схему так, чтобы комментарии и фон были одного цвета, создавать скрипты для фильтрации комментариев и т.п. Чтобы уберечь код от таких неправильных применений изобретательности программиста и уменьшить риск игнорирования комментариев, имеющих подлинную ценность, комментарии должны рассматриваться как код. Каждый комментарий должен приносить пользу читателю, иначе это мусор, который следует удалить или переписать.
Что же квалифицируется как ценность? Комментарии должны сказать что-то, что код не может выразить. Комментарий, объясняющий то, о чём уже должен говорить блок кода, свидетельствует о том, что нужно изменить структуру кода или соглашения о кодировании, чтобы код говорил сам за себя. Вместо того, чтобы объяснять плохие имена методов или классов, переименуйте их. Вместо того, чтобы комментировать отдельные блоки в длинной функции, разбейте функцию на меньшие по размеру, чьи имена отражают намерения этих блоков. Попробуйте выразить как можно больше через код. Каждое место, которое нельзя выразить в коде так же хорошо, как естественным языком, становится кандидатом на добавление полезного комментария. Комментируйте лишь то, что код не может сообщить в принципе, а не объясняйте то, что он не сообщает сейчас.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Kelvin Henney
97 Вещей, Которые Должен Знать Каждый Программист
17. Комментируйте только то, что код не может выразить
Разница между теорией и практикой гораздо очевиднее на практике, чем в теории – это как нельзя лучше относится к комментариям. Теоретически идея комментирования кода звучит убедительно: предложить читателю подробности, объяснение того, что происходит в коде. Что может быть полезнее, чем полезная добавка? Однако на практике комментарии часто становятся проблемой. Как и в любой другой форме письма, нужно уметь писать хорошие комментарии. В основном это умение заключается в том, чтобы знать, когда их не писать.
Когда код некорректен, компиляторы, интерпретаторы и другие инструменты обязательно найдут ошибку. Если код каким-либо образом некорректен в функциональном отношении, обзоры кода, статический анализ, тесты и повседневное использование в производственной среде устранят большинство ошибок. Но что насчет комментариев? В книге “The Elements of Programming Style” Керниган и Плаугер отмечают, что «комментарий имеет нулевую (или отрицательную) ценность, если он неправильный». И всё же такие комментарии часто засоряют код и остаются там даже дольше, чем ошибки. Они являются постоянной причиной отвлечения и источником дезинформации - маленьким, но препятствием в работе программиста.
Что можно сказать о комментариях, которые не являются технически неправильными, но не добавляют никакой ценности к коду? Такие комментарии являются шумом. Комментарии, которые повторяют код, не добавляют ничего полезного для читателя: сообщение о чём-либо один раз в коде и ещё раз на естественном языке не делает код более правильным или более красивым. Закомментированный код не выполняется, поэтому он не несёт никакой пользы ни для читателя, ни для среды исполнения. Такие комментарии также очень быстро устаревают. Комментарии, связанные с версией программы и закомментированный код пытаются рассказать о версиях и истории программы. На эти вопросы уже отвечают (гораздо более эффективно) инструменты контроля версий.
Большое количество бесполезных и неправильных комментариев в коде побуждает программистов игнорировать вообще все комментарии, либо пропуская их, либо принимая активные меры, чтобы их скрыть. Программисты находчивы и будут обходить всё, что воспринимается ими как помеха: скрывать комментарии, изменять цветовую схему так, чтобы комментарии и фон были одного цвета, создавать скрипты для фильтрации комментариев и т.п. Чтобы уберечь код от таких неправильных применений изобретательности программиста и уменьшить риск игнорирования комментариев, имеющих подлинную ценность, комментарии должны рассматриваться как код. Каждый комментарий должен приносить пользу читателю, иначе это мусор, который следует удалить или переписать.
Что же квалифицируется как ценность? Комментарии должны сказать что-то, что код не может выразить. Комментарий, объясняющий то, о чём уже должен говорить блок кода, свидетельствует о том, что нужно изменить структуру кода или соглашения о кодировании, чтобы код говорил сам за себя. Вместо того, чтобы объяснять плохие имена методов или классов, переименуйте их. Вместо того, чтобы комментировать отдельные блоки в длинной функции, разбейте функцию на меньшие по размеру, чьи имена отражают намерения этих блоков. Попробуйте выразить как можно больше через код. Каждое место, которое нельзя выразить в коде так же хорошо, как естественным языком, становится кандидатом на добавление полезного комментария. Комментируйте лишь то, что код не может сообщить в принципе, а не объясняйте то, что он не сообщает сейчас.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Kelvin Henney
День триста сорок второй.
Сегодня расскажу о паре интересных ресурсов для обучения.
Первый (вполне прозаично) – Microsoft Learn. Ресурс относительно новый, насколько я понимаю, пришёл на смену Microsoft Virtual Academy. Пока, как мне показалось на первый взгляд, там не так много информации, однако всё равно можно найти много интересного. Ресурс построен по принципу курсов: можно отслеживать прогресс (прочитанные статьи отмечаются). Кроме того, даются очки репутации и уровень. И хотя очки добавляются просто по мере открытия страниц курсов, без проверки ваших знаний, но возможно даже это послужит дополнительным стимулом.
Пока всё только на английском, но надеюсь, что в Майкрософт займутся локализацией рано или поздно.
Карта знаний .NET Web программиста
Авторы описывают ресурс как «Детализированную карту знаний для .NET Web программистов от Trainee до Senior.». И это действительно гигантский список, охватывающий язык C#, платформу .Net, принципы проектирования и написания кода, модульное тестирование, ASP.NET, микросервисы, фронтенд разработку, базы данных, облачные сервисы (похвастаюсь, добавили после моего комментария 😊), системы контроля версий и многое другое со ссылками либо на статьи или курсы в сети, либо на книги (с точностью до главы), где можно найти эту информацию.
В списке звёздочками обозначены темы, которые "должен знать" программист определённого уровня (интерн, джун, мидл или сеньор). От себя хочу заметить, что не стоит воспринимать этот список как обязательный (маст-ноу). Там такой объём информации, что, на мой взгляд, одному фулл-стек специалисту охватить всё это просто нереально. Но это нисколько не снижает ценность ресурса. Использовать его как справочник очень полезно. Добавил себе в закладки.
Список приведён как на русском, так и на английском, но сразу предупреждаю, что далеко не все ссылки ведут на русскоязычные источники (такова се ля ви).
ПС: За ссылку на второй ресурс большое спасибо участнику нашего чата @fjod10199.
Сегодня расскажу о паре интересных ресурсов для обучения.
Первый (вполне прозаично) – Microsoft Learn. Ресурс относительно новый, насколько я понимаю, пришёл на смену Microsoft Virtual Academy. Пока, как мне показалось на первый взгляд, там не так много информации, однако всё равно можно найти много интересного. Ресурс построен по принципу курсов: можно отслеживать прогресс (прочитанные статьи отмечаются). Кроме того, даются очки репутации и уровень. И хотя очки добавляются просто по мере открытия страниц курсов, без проверки ваших знаний, но возможно даже это послужит дополнительным стимулом.
Пока всё только на английском, но надеюсь, что в Майкрософт займутся локализацией рано или поздно.
Карта знаний .NET Web программиста
Авторы описывают ресурс как «Детализированную карту знаний для .NET Web программистов от Trainee до Senior.». И это действительно гигантский список, охватывающий язык C#, платформу .Net, принципы проектирования и написания кода, модульное тестирование, ASP.NET, микросервисы, фронтенд разработку, базы данных, облачные сервисы (похвастаюсь, добавили после моего комментария 😊), системы контроля версий и многое другое со ссылками либо на статьи или курсы в сети, либо на книги (с точностью до главы), где можно найти эту информацию.
В списке звёздочками обозначены темы, которые "должен знать" программист определённого уровня (интерн, джун, мидл или сеньор). От себя хочу заметить, что не стоит воспринимать этот список как обязательный (маст-ноу). Там такой объём информации, что, на мой взгляд, одному фулл-стек специалисту охватить всё это просто нереально. Но это нисколько не снижает ценность ресурса. Использовать его как справочник очень полезно. Добавил себе в закладки.
Список приведён как на русском, так и на английском, но сразу предупреждаю, что далеко не все ссылки ведут на русскоязычные источники (такова се ля ви).
ПС: За ссылку на второй ресурс большое спасибо участнику нашего чата @fjod10199.
День триста сорок третий. #ЗаметкиНаПолях
Отложенная (ленивая) инициализация
Ленивая инициализация объекта означает, что его создание откладывается до его первого использования. Она в основном используется для повышения производительности, предотвращения ненужных вычислений и снижения потребления памяти программой. Наиболее распространённые сценарии:
- Ресурсоёмкий объект, который программа может и не использовать. Например, объект
- Ресурсоёмкий объект, создание которого можно отложить. Например, программа загружает несколько экземпляров объекта при запуске, но только некоторые из них требуются немедленно. Можно ускорить запуск программы, отложив инициализацию ненужных объектов до тех пор, пока они не понадобятся.
Базовое использование
-
-
-
После создания объекта
Чтобы реализовать открытое свойство с помощью отложенной инициализации, определите вспомогательное поле свойства как
- создать новое лямбда-выражение, возвращающее переданное мутатору значение,
- передать выражение в конструктор нового объекта
- присвоить новый объект вспомогательному полю.
Тогда последующее обращение к аксессору (get) свойства приведёт к новой инициализации ленивого объекта и вернёт новое значение.
Источник: https://docs.microsoft.com/en-us/dotnet/framework/performance/lazy-initialization
Отложенная (ленивая) инициализация
Ленивая инициализация объекта означает, что его создание откладывается до его первого использования. Она в основном используется для повышения производительности, предотвращения ненужных вычислений и снижения потребления памяти программой. Наиболее распространённые сценарии:
- Ресурсоёмкий объект, который программа может и не использовать. Например, объект
Customer
со свойством Orders
(массив заказов), для инициализации которого требуется запрос из базы данных. Если пользователю не нужны заказы, то нет причин тратить память или время на создание массива Orders
. Используя Lazy<Orders>
, чтобы объявить отложенную инициализацию объекта Orders
, можно избежать расхода системных ресурсов на неиспользуемый объект.- Ресурсоёмкий объект, создание которого можно отложить. Например, программа загружает несколько экземпляров объекта при запуске, но только некоторые из них требуются немедленно. Можно ускорить запуск программы, отложив инициализацию ненужных объектов до тех пор, пока они не понадобятся.
Базовое использование
Lazy<Orders> orders = new Lazy<Orders>();В этом случае объект параметра типа создаётся при первом использовании (обращении к свойству
...
var listOfOrders = orders.Value; //использование
Value
) с помощью Activator.CreateInstance
, а сам тип Orders
должен иметь конструктор без параметров. Кроме того, ленивому конструктору можно передать параметры:-
bool isThreadSafe
– по умолчанию true
, то есть создаётся потокобезопасный объект. Первый поток инициализирует объект, далее все потоки используют одни и те же данные. Если предполагается использование в единственном потоке, значение false
позволяет получить небольшой выигрыш в быстродействии.-
Func<Orders> valueFactory
- лямбда-выражение, позволяющее выполнить любые действия, необходимые для инициализации объекта (см. пример ниже).-
Orders value
– предварительно инициализированное значение.После создания объекта
Lazy
экземпляр Orders
не создается до первого доступа к свойству Value
переменной orders
. Объект Lazy<T>
всегда возвращает тот же объект или значение, которые использовались для его инициализации. Следовательно, свойство Value
доступно только для чтения.Чтобы реализовать открытое свойство с помощью отложенной инициализации, определите вспомогательное поле свойства как
Lazy<T>
и верните свойство Value
из аксессора (get) свойства:class Customer {Поскольку свойство
private Lazy<Orders> orders;
public string CustomerID {get; private set;}
public Customer(string id) {
CustomerID = id;
orders = new Lazy<Orders>(() =>
{
// дополнительная логика инициализации
return new Orders(this.CustomerID);
});
}
public Orders MyOrders {
get {
return orders.Value;
}
}
}
Value
доступно только для чтения, у свойства Orders нет мутатора (set). Изменить значение ленивого объекта нельзя, можно только инициализировать новый объект. Если требуется изменяемое ленивое свойство, мутатор должен:- создать новое лямбда-выражение, возвращающее переданное мутатору значение,
- передать выражение в конструктор нового объекта
Lazy<T>
,- присвоить новый объект вспомогательному полю.
Тогда последующее обращение к аксессору (get) свойства приведёт к новой инициализации ленивого объекта и вернёт новое значение.
Источник: https://docs.microsoft.com/en-us/dotnet/framework/performance/lazy-initialization
День триста сорок четвёртый. #DesignPatterns
Паттерны проектирования
7. Паттерн «Команда» (Command).
Паттерн «Команда» позволяет спрятать действие в объекте и отвязать источник этого действия от места его исполнения.
Назначение: инкапсулирует запрос как объект, позволяя тем самым задавать параметры клиентов для обработки соответствующих запросов, ставить запросы в очередь или протоколировать их, а также поддерживать отмену операций.
Варианты использования:
- Система управляется событиями. При появлении такого события (запроса) необходимо выполнить определённую последовательность действий. Например, в пользовательском интерфейсе пункт меню не должен знать, что происходит при его активизации пользователем, он должен знать лишь о некотором действии, которое нужно выполнить при нажатии кнопки. Кроме того, то же действие можно выполнять при нажатии комбинации клавиш.
- Необходимо параметризировать объекты выполняемым действием, ставить запросы в очередь, хранить историю запросов или поддерживать операции отмены (undo) и повтора (redo) действий.
Классическая диаграмма приведена на рисунке ниже:
-
-
-
-
-
Аналогией паттерна «Команда» из жизни может быть ресторан. Клиент делает заказ (команду) официанту (инициатору), который передаёт её повару (получателю). Повар не знает, кто конкретно послал ему заказ. Но это ему безразлично, так как вся необходимая информация есть в листе заказа.
Существует две основные реализации паттерна:
- Делегирующая команда, представленная выше, не выполняет операцию самостоятельно, но знает, кто это может сделать, поэтому вызывает метод получателя, содержащий бизнес-логику.
- Самостоятельная команда содержит бизнес-логику внутри самого объекта команды.
Помимо объектно-ориентированной версии, в языке C# очень распространено использование функциональной версии паттерна «Команда» на основе делегатов. С помощью анонимных методов легко получить делегат, который будет захватывать внешний контекст и выполнять требуемое действие.
Источники:
- Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 7.
- https://refactoring.guru/ru/design-patterns/command
- https://metanit.com/sharp/patterns/3.3.php
Паттерны проектирования
7. Паттерн «Команда» (Command).
Паттерн «Команда» позволяет спрятать действие в объекте и отвязать источник этого действия от места его исполнения.
Назначение: инкапсулирует запрос как объект, позволяя тем самым задавать параметры клиентов для обработки соответствующих запросов, ставить запросы в очередь или протоколировать их, а также поддерживать отмену операций.
Варианты использования:
- Система управляется событиями. При появлении такого события (запроса) необходимо выполнить определённую последовательность действий. Например, в пользовательском интерфейсе пункт меню не должен знать, что происходит при его активизации пользователем, он должен знать лишь о некотором действии, которое нужно выполнить при нажатии кнопки. Кроме того, то же действие можно выполнять при нажатии комбинации клавиш.
- Необходимо параметризировать объекты выполняемым действием, ставить запросы в очередь, хранить историю запросов или поддерживать операции отмены (undo) и повтора (redo) действий.
Классическая диаграмма приведена на рисунке ниже:
-
Client
– создаёт объекты конкретных команд, передавая в них все необходимые параметры, среди которых могут быть и ссылки на объекты получателей.-
Invoker
– инициатор команды. Хранит ссылку на объект команды и обращается к нему, когда нужно выполнить какое-то действие.-
Receiver
- получатель команды. Определяет действия, которые должны выполняться в результате запроса.-
Command
- интерфейс, представляющий команду. Обычно определяет метод Execute()
для выполнения действия, который может принимать необязательный контекст исполнения. Также нередко включает метод Undo()
, реализация которого должна заключаться в отмене действия команды.-
ConcreteCommand
- конкретная реализация команды, реализует метод Execute()
, в котором вызывается метод Action()
получателя. Также команда может хранить состояние (параметры, с которыми должен быть вызван метод объекта-получателя).Аналогией паттерна «Команда» из жизни может быть ресторан. Клиент делает заказ (команду) официанту (инициатору), который передаёт её повару (получателю). Повар не знает, кто конкретно послал ему заказ. Но это ему безразлично, так как вся необходимая информация есть в листе заказа.
Существует две основные реализации паттерна:
- Делегирующая команда, представленная выше, не выполняет операцию самостоятельно, но знает, кто это может сделать, поэтому вызывает метод получателя, содержащий бизнес-логику.
- Самостоятельная команда содержит бизнес-логику внутри самого объекта команды.
Помимо объектно-ориентированной версии, в языке C# очень распространено использование функциональной версии паттерна «Команда» на основе делегатов. С помощью анонимных методов легко получить делегат, который будет захватывать внешний контекст и выполнять требуемое действие.
Источники:
- Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 7.
- https://refactoring.guru/ru/design-patterns/command
- https://metanit.com/sharp/patterns/3.3.php
👍1
День триста сорок пятый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
18. Непрерывное обучение
Мы живём в интересное время. Разработка ПО доступна практически из любой точки мира, поэтому для вас не должно быть секретом, что есть много людей, способных выполнять вашу работу. Вы должны продолжать учиться, чтобы оставаться конкурентоспособным. В противном случае вы станете динозавром, застрявшего на одной работе, пока однажды в вас не отпадёт необходимость, либо ваша работа не станет выполняться более дешёвым способом.
Что же делать? Некоторые работодатели достаточно щедры, чтобы обеспечить обучение сотрудников, другие могут не иметь возможности делать это. Чтобы не рисковать, вы должны взять ответственность за своё образование на себя.
Вот список способов чему-нибудь научиться. Многие из них можно найти в Интернете бесплатно:
1. Читайте книги, журналы, блоги, телеграм-каналы 😉 и веб-сайты. Если вы хотите углубиться в тему, подпишитесь на рассылку новостей.
2. Если вы действительно хотите погрузиться в технологию, попробуйте написать немного кода.
3. Всегда старайтесь работать с наставником, потому что быть лучшим в команде может помешать вашему развитию. Хотя научиться чему-то можно у кого угодно, вы можете узнать намного больше от кого-то, кто умнее или опытнее, чем вы. Если вы не можете найти наставника в своей команде, подумайте над тем, чтобы двигаться дальше.
4. Используйте виртуальных наставников. Найдите в сети авторов и разработчиков, которые вам действительно нравятся, и изучите всё, что они пишут. Подпишитесь на их блоги.
5. Познакомьтесь с фреймворками и библиотеками, которые вы используете. Зная, как что-то работает, вы узнаете, как использовать это лучше. Если эти инструменты с открытым исходным кодом, вам действительно повезло. Используйте отладчик, чтобы пройтись по коду и увидеть, что происходит «под капотом». Вы увидите код, написанный и проверенный действительно умными людьми.
6. Всякий раз, когда вы делаете ошибку, исправляете ошибку или сталкиваетесь с проблемой, постарайтесь по-настоящему разобраться, что произошло. Вполне вероятно, что кто-то уже сталкивался с такой же проблемой и опубликовал решение в сети.
7. Хороший способ чему-то научиться - учить или говорить об этом. Когда люди будут слушать вас и задавать вопросы, у вас будет высокая мотивация к обучению. Попробуйте «обучение за ланчем» на работе, в группе соцсети или на местной конференции.
8. Присоединитесь или создайте группу (сообщество) для языка, технологии или дисциплины, которые вас интересуют.
9. Посещайте конференции. Если нет возможности посетить, многие конференции размещают выступления в сети бесплатно.
10. Далеко ездите? Слушайте подкасты в дороге.
11. Вы когда-нибудь запускали инструмент статического анализа кода или просматривали предупреждения в вашей IDE? Разберитесь, что они сообщают и почему.
12. Следуйте советам «Программистов-прагматиков» и изучайте новый язык каждый год. По крайней мере, изучите новую технологию или инструмент. Расширение кругозора даст вам новые идеи, которые вы можете использовать в своей текущей работе.
13. Не всё, что вы изучаете, должно быть о технологиях. Изучите домен, в котором вы работаете, чтобы лучше понять требования и помочь решить бизнес-проблему. Изучение того, как повысить свою производительность – еще одна очень полезная вещь, которую не стоит игнорировать.
Возвращайтесь в школу. Было бы неплохо иметь возможность, как у Нео в Матрице, просто загружать необходимую нам информацию в мозг. Но мы этого не умеем, поэтому нам требуется время. Не нужно тратить на обучение всё свободное время, но стоит делать это регулярно. Немного времени даже раз в неделю всё равно лучше, чем ничего. Но не забывайте, что есть и жизнь помимо работы.
Технология быстро меняется. Не отставайте.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Clint Shank
97 Вещей, Которые Должен Знать Каждый Программист
18. Непрерывное обучение
Мы живём в интересное время. Разработка ПО доступна практически из любой точки мира, поэтому для вас не должно быть секретом, что есть много людей, способных выполнять вашу работу. Вы должны продолжать учиться, чтобы оставаться конкурентоспособным. В противном случае вы станете динозавром, застрявшего на одной работе, пока однажды в вас не отпадёт необходимость, либо ваша работа не станет выполняться более дешёвым способом.
Что же делать? Некоторые работодатели достаточно щедры, чтобы обеспечить обучение сотрудников, другие могут не иметь возможности делать это. Чтобы не рисковать, вы должны взять ответственность за своё образование на себя.
Вот список способов чему-нибудь научиться. Многие из них можно найти в Интернете бесплатно:
1. Читайте книги, журналы, блоги, телеграм-каналы 😉 и веб-сайты. Если вы хотите углубиться в тему, подпишитесь на рассылку новостей.
2. Если вы действительно хотите погрузиться в технологию, попробуйте написать немного кода.
3. Всегда старайтесь работать с наставником, потому что быть лучшим в команде может помешать вашему развитию. Хотя научиться чему-то можно у кого угодно, вы можете узнать намного больше от кого-то, кто умнее или опытнее, чем вы. Если вы не можете найти наставника в своей команде, подумайте над тем, чтобы двигаться дальше.
4. Используйте виртуальных наставников. Найдите в сети авторов и разработчиков, которые вам действительно нравятся, и изучите всё, что они пишут. Подпишитесь на их блоги.
5. Познакомьтесь с фреймворками и библиотеками, которые вы используете. Зная, как что-то работает, вы узнаете, как использовать это лучше. Если эти инструменты с открытым исходным кодом, вам действительно повезло. Используйте отладчик, чтобы пройтись по коду и увидеть, что происходит «под капотом». Вы увидите код, написанный и проверенный действительно умными людьми.
6. Всякий раз, когда вы делаете ошибку, исправляете ошибку или сталкиваетесь с проблемой, постарайтесь по-настоящему разобраться, что произошло. Вполне вероятно, что кто-то уже сталкивался с такой же проблемой и опубликовал решение в сети.
7. Хороший способ чему-то научиться - учить или говорить об этом. Когда люди будут слушать вас и задавать вопросы, у вас будет высокая мотивация к обучению. Попробуйте «обучение за ланчем» на работе, в группе соцсети или на местной конференции.
8. Присоединитесь или создайте группу (сообщество) для языка, технологии или дисциплины, которые вас интересуют.
9. Посещайте конференции. Если нет возможности посетить, многие конференции размещают выступления в сети бесплатно.
10. Далеко ездите? Слушайте подкасты в дороге.
11. Вы когда-нибудь запускали инструмент статического анализа кода или просматривали предупреждения в вашей IDE? Разберитесь, что они сообщают и почему.
12. Следуйте советам «Программистов-прагматиков» и изучайте новый язык каждый год. По крайней мере, изучите новую технологию или инструмент. Расширение кругозора даст вам новые идеи, которые вы можете использовать в своей текущей работе.
13. Не всё, что вы изучаете, должно быть о технологиях. Изучите домен, в котором вы работаете, чтобы лучше понять требования и помочь решить бизнес-проблему. Изучение того, как повысить свою производительность – еще одна очень полезная вещь, которую не стоит игнорировать.
Возвращайтесь в школу. Было бы неплохо иметь возможность, как у Нео в Матрице, просто загружать необходимую нам информацию в мозг. Но мы этого не умеем, поэтому нам требуется время. Не нужно тратить на обучение всё свободное время, но стоит делать это регулярно. Немного времени даже раз в неделю всё равно лучше, чем ничего. Но не забывайте, что есть и жизнь помимо работы.
Технология быстро меняется. Не отставайте.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Clint Shank