Если_бы_программисты_строили_дома.pdf
96.6 KB
День шестьсот двадцать пятый. #Юмор
Олды тут? Вон чего откопал в старых документах. Помню, дико популярны были такие «Хроники» в начале 2000х. Решил молодость вспомнить)))
Если понравится, пишите в комментариях, ещё выложу чего-нибудь. Хорошей пятницы.
https://telegra.ph/Esli-by-programmisty-stroili-doma-10-16
Олды тут? Вон чего откопал в старых документах. Помню, дико популярны были такие «Хроники» в начале 2000х. Решил молодость вспомнить)))
Если понравится, пишите в комментариях, ещё выложу чего-нибудь. Хорошей пятницы.
https://telegra.ph/Esli-by-programmisty-stroili-doma-10-16
День шестьсот двадцать шестой. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
63. Используйте Типы Специфичные для Домена Вместо Примитивных
23 сентября 1999г. Mars Climate Orbiter стоимостью 327,6 млн долларов был потерян при выходе на орбиту Марса из-за ошибки в программном обеспечении на Земле. Позднее выяснили, что перепутали единицы измерения. Программное обеспечение на Земле, поставленное компанией Локхид-Мартин, подавало команды аппарату, используя британские единицы силы фунты, в то время как космический корабль, сделанный в НАСА, ожидал принятые в системе СИ ньютоны. Из-за этого наземная станция недооценила мощность двигателей космического корабля почти в 4,5 раза. Эта неудача считается одной из причин окончательного и полного перехода NASA на метрическую систему, объявленного в 2007 году.
Это один из многих примеров сбоев программного обеспечения, которые можно было бы предотвратить, если бы применялась более строгая и специфичная для домена типизация. Это также объясняет наличие многих функций языка Ada, одной из основных целей разработки которого было создание программного обеспечения с высокими требованиями к безопасности. В Ada есть строгая типизация со статической проверкой как для примитивных, так и для определённых пользователем типов.
Если
а
Разработчики, работающие в менее требовательных к безопасности доменах, также могут извлечь выгоду из применения более специфичной для предметной области типизации, где в противном случае они могли бы продолжать использовать примитивные типы данных, такие как строки и числа с плавающей точкой. В Java, C++, C#, Python и других современных языках абстрактный тип данных известен как класс. Использование таких классов, как
- Код становится более читабельным, поскольку он выражает намерения в терминах домена, а не в виде общих Float или String.
- Код становится более тестируемым, поскольку легче тестировать инкапсулированное поведение.
- Упрощается повторное использование в приложениях и системах.
Этот подход одинаково применим как в статически, так и в динамически типизированных языках. Единственное отличие состоит в том, что разработчики, использующие языки со статической типизацией, получают некоторую помощь от компилятора, в то время как разработчики, использующие языки с динамической типизацией, с должны больше полагаться на модульные тесты. Стиль проверки может быть разным, но мотивация и стиль выражений - нет.
Мораль в том, что для повышения качества вашего программного обеспечения стоит использовать типы, специфичные для предметной области.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Einar Landre
97 Вещей, Которые Должен Знать Каждый Программист
63. Используйте Типы Специфичные для Домена Вместо Примитивных
23 сентября 1999г. Mars Climate Orbiter стоимостью 327,6 млн долларов был потерян при выходе на орбиту Марса из-за ошибки в программном обеспечении на Земле. Позднее выяснили, что перепутали единицы измерения. Программное обеспечение на Земле, поставленное компанией Локхид-Мартин, подавало команды аппарату, используя британские единицы силы фунты, в то время как космический корабль, сделанный в НАСА, ожидал принятые в системе СИ ньютоны. Из-за этого наземная станция недооценила мощность двигателей космического корабля почти в 4,5 раза. Эта неудача считается одной из причин окончательного и полного перехода NASA на метрическую систему, объявленного в 2007 году.
Это один из многих примеров сбоев программного обеспечения, которые можно было бы предотвратить, если бы применялась более строгая и специфичная для домена типизация. Это также объясняет наличие многих функций языка Ada, одной из основных целей разработки которого было создание программного обеспечения с высокими требованиями к безопасности. В Ada есть строгая типизация со статической проверкой как для примитивных, так и для определённых пользователем типов.
Если
VelocityInKnots
представляет собой Float
в диапазоне от 0.0
до 500.00
,а
DistanceInNauticalMiles
- Float
от 0.0
до 3000.00
, то следующий код:SomeNumber : Float;приведёт к ошибке компиляции.
SomeNumber := DistanceInNauticalMiles + VelocityInKnots;
Разработчики, работающие в менее требовательных к безопасности доменах, также могут извлечь выгоду из применения более специфичной для предметной области типизации, где в противном случае они могли бы продолжать использовать примитивные типы данных, такие как строки и числа с плавающей точкой. В Java, C++, C#, Python и других современных языках абстрактный тип данных известен как класс. Использование таких классов, как
VelocityInKnots
и DistanceInNauticalMiles
, серьёзно повысит качество кода:- Код становится более читабельным, поскольку он выражает намерения в терминах домена, а не в виде общих Float или String.
- Код становится более тестируемым, поскольку легче тестировать инкапсулированное поведение.
- Упрощается повторное использование в приложениях и системах.
Этот подход одинаково применим как в статически, так и в динамически типизированных языках. Единственное отличие состоит в том, что разработчики, использующие языки со статической типизацией, получают некоторую помощь от компилятора, в то время как разработчики, использующие языки с динамической типизацией, с должны больше полагаться на модульные тесты. Стиль проверки может быть разным, но мотивация и стиль выражений - нет.
Мораль в том, что для повышения качества вашего программного обеспечения стоит использовать типы, специфичные для предметной области.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Einar Landre
День шестьсот двадцать седьмой. #Оффтоп
Вот вам тема для воскресного обсуждения: «Как получить повышение в должности разработчика?»
Ниже приведу мой пересказ видео с ютуба (ссылка внизу). Все эти советы, конечно, элементарные, сферические в вакууме, взяты на примере западного рынка, поэтому не учитывают нашу специфику, и вообще, вроде бы проще переходить с повышением в другую компанию, и тэдэ, и тэпэ. Но это просто в качестве затравки.
1. Узнайте правила или критерии для повышения
Многие разработчики тратят огромные усилия, выполняя (и хорошо выполняя) работу, которая не расценивается в компании, как критерий для повышения. Если вы исправляете множество мелких недочётов в ПО, вы можете считать, что по количеству исправленных тикетов вы чемпион, но в компании могут цениться совсем другие качества. В гигантах, вроде FAGMA, есть чёткая градация уровней и список требований к квалификации на каждом уровне. В небольших компаниях вы можете прямо спросить об этом тимлида, начальника отдела или коллегу, которого недавно повысили.
2. Работайте на уровне, которого хотите достичь при повышении
Нет смысла быть высококлассным джуном. Нужно работать на уровне, требуемом от мидла, чтобы команда видела, что вы по факту превосходите уровень джуна. По мере роста вашей квалификации вам должно требоваться гораздо меньше подробностей в описании задачи, чтобы её выполнить. Джуну может требоваться описание, какие классы или таблицы БД создать, как реализовать тот или иной функционал. Более опытные разработчики принимают архитектурные и дизайнерские решения самостоятельно.
3. Ищите возможности
Чем выше должность в иерархии, тем объёмнее и серьёзнее задачи, которые выполняет специалист. Но и количество таких задач меньше. Как же их заполучить? Посещайте собрания, говорите с коллегами и менеджерами, предлагайте свои идеи. Проще говоря, повышайте софт скилы.
4. Не упускайте возможности
Не бойтесь нового, не бойтесь браться за незнакомые или сложные проекты (хотя, трезво оценивая свои силы, конечно). Но, если уж взялись, доводите дело до конца.
5. Дайте знать окружающим о своей работе
Этого разработчики обычно не любят, но без этого никуда. Ваши коллеги, а, главное, ваши начальники должны знать о том, что вы делаете и какие усилия вы прикладываете. Многие путают это с офисными интригами, подсиживанием коллег и присваиванием чужих результатов. Нет, не будьте такими. Здесь речь идёт исключительно о ваших заслугах и вашем вкладе в общее дело. Убедитесь, что ваши начальники в курсе. А это означает, что нужно поддерживать с ними связь и хорошие отношения. Снова софт скиллз.
6. Усердно работайте
«Спасибо, кэп», - скажете вы. Но факт остаётся фактом. Повышение – это не только «лычка» и больше денег, но и больше работы и ответственности. Повышения «за выслугу лет», конечно, случаются, но это скорее исключения.
В комментариях предлагаю вам описать свой опыт. Как вам удалось добиться повышения? Это было в крупной или небольшой компании? Какими советами вы можете поделиться?
Источник: https://www.youtube.com/watch?v=vm4OsDPK1gA
Вот вам тема для воскресного обсуждения: «Как получить повышение в должности разработчика?»
Ниже приведу мой пересказ видео с ютуба (ссылка внизу). Все эти советы, конечно, элементарные, сферические в вакууме, взяты на примере западного рынка, поэтому не учитывают нашу специфику, и вообще, вроде бы проще переходить с повышением в другую компанию, и тэдэ, и тэпэ. Но это просто в качестве затравки.
1. Узнайте правила или критерии для повышения
Многие разработчики тратят огромные усилия, выполняя (и хорошо выполняя) работу, которая не расценивается в компании, как критерий для повышения. Если вы исправляете множество мелких недочётов в ПО, вы можете считать, что по количеству исправленных тикетов вы чемпион, но в компании могут цениться совсем другие качества. В гигантах, вроде FAGMA, есть чёткая градация уровней и список требований к квалификации на каждом уровне. В небольших компаниях вы можете прямо спросить об этом тимлида, начальника отдела или коллегу, которого недавно повысили.
2. Работайте на уровне, которого хотите достичь при повышении
Нет смысла быть высококлассным джуном. Нужно работать на уровне, требуемом от мидла, чтобы команда видела, что вы по факту превосходите уровень джуна. По мере роста вашей квалификации вам должно требоваться гораздо меньше подробностей в описании задачи, чтобы её выполнить. Джуну может требоваться описание, какие классы или таблицы БД создать, как реализовать тот или иной функционал. Более опытные разработчики принимают архитектурные и дизайнерские решения самостоятельно.
3. Ищите возможности
Чем выше должность в иерархии, тем объёмнее и серьёзнее задачи, которые выполняет специалист. Но и количество таких задач меньше. Как же их заполучить? Посещайте собрания, говорите с коллегами и менеджерами, предлагайте свои идеи. Проще говоря, повышайте софт скилы.
4. Не упускайте возможности
Не бойтесь нового, не бойтесь браться за незнакомые или сложные проекты (хотя, трезво оценивая свои силы, конечно). Но, если уж взялись, доводите дело до конца.
5. Дайте знать окружающим о своей работе
Этого разработчики обычно не любят, но без этого никуда. Ваши коллеги, а, главное, ваши начальники должны знать о том, что вы делаете и какие усилия вы прикладываете. Многие путают это с офисными интригами, подсиживанием коллег и присваиванием чужих результатов. Нет, не будьте такими. Здесь речь идёт исключительно о ваших заслугах и вашем вкладе в общее дело. Убедитесь, что ваши начальники в курсе. А это означает, что нужно поддерживать с ними связь и хорошие отношения. Снова софт скиллз.
6. Усердно работайте
«Спасибо, кэп», - скажете вы. Но факт остаётся фактом. Повышение – это не только «лычка» и больше денег, но и больше работы и ответственности. Повышения «за выслугу лет», конечно, случаются, но это скорее исключения.
В комментариях предлагаю вам описать свой опыт. Как вам удалось добиться повышения? Это было в крупной или небольшой компании? Какими советами вы можете поделиться?
Источник: https://www.youtube.com/watch?v=vm4OsDPK1gA
День шестьсот двадцать восьмой. #ЗаметкиНаПолях #AsyncAwaitFAQ
Самые Частые Ошибки при Работе с async/await. Начало 1-4
1. Лишний async/await
Использование ключевых слов async/await приводит к неявному выделению памяти под конечный автомат, который отвечает за организацию асинхронных вызовов. Когда ожидаемое выражение является единственным или последним оператором в функции, его можно пропустить. Однако с этим есть несколько проблем, о которых вам следует знать.
❌ Неверно
Если мы используем асинхронный код, мы всегда должны использовать асинхронные методы, если они существуют. Многие API предлагают асинхронные аналоги своих хорошо известных синхронных методов.
❌ Неверно
Есть две причины, по которым
- Вызывающий код не может ожидать метод
- Невозможно обработать исключение, вызванное этим методом. Если возникает исключение, ваш процесс падает!
Вы всегда должны использовать
❌ Неверно
Если передать асинхронную лямбда-функцию в качестве аргумента типа
- изменить тип параметра с
- реализовать этот делегат синхронно.
Стоит отметить, что некоторые API-интерфейсы уже предоставляют аналоги своих методов, которые принимают
Источник: https://cezarypiatek.github.io/post/async-analyzers-p1/
Самые Частые Ошибки при Работе с async/await. Начало 1-4
1. Лишний async/await
Использование ключевых слов async/await приводит к неявному выделению памяти под конечный автомат, который отвечает за организацию асинхронных вызовов. Когда ожидаемое выражение является единственным или последним оператором в функции, его можно пропустить. Однако с этим есть несколько проблем, о которых вам следует знать.
❌ Неверно
async Task DoSomethingAsync(){✅ Верно
await Task.Yield();
}
Task DoSomethingAsync() {2. Вызов синхронного метода внутри асинхронного метода
return Task.Yield();
}
Если мы используем асинхронный код, мы всегда должны использовать асинхронные методы, если они существуют. Многие API предлагают асинхронные аналоги своих хорошо известных синхронных методов.
❌ Неверно
async Task DoAsync(Stream file, byte[] buffer) {✅ Верно
file.Read(buffer, 0, 10);
}
async Task DoAsync(Stream file, byte[] buffer) {3. Использование async void
await file.ReadAsync(buffer, 0, 10);
}
Есть две причины, по которым
async void
вреден:- Вызывающий код не может ожидать метод
async void
.- Невозможно обработать исключение, вызванное этим методом. Если возникает исключение, ваш процесс падает!
Вы всегда должны использовать
async Task
вместо async void
, если только это не обработчик событий, но тогда вы должны гарантировать себе, что метод не выбросит исключения.❌ Неверно
async void DoSomethingAsync() {✅ Верно
await Task.Yield();
}
async Task DoSomethingAsync() {4. Неподдерживаемые асинхронные делегаты
await Task.Yield();
}
Если передать асинхронную лямбда-функцию в качестве аргумента типа
Action
, компилятор сгенерирует метод async void
, недостатки которого были описаны выше. Есть два решения этой проблемы:- изменить тип параметра с
Action
на Func<Task>
, - реализовать этот делегат синхронно.
Стоит отметить, что некоторые API-интерфейсы уже предоставляют аналоги своих методов, которые принимают
Func<Task>.
void DoSomething() {
Callback(async() => {
await Task.Yield();
});
}
❌ Неверноvoid Callback(Action action){…}✅ Верно
void Callback(Func<Task> action){…}Продолжение следует…
Источник: https://cezarypiatek.github.io/post/async-analyzers-p1/
👍1
День шестьсот двадцать девятый. #ЗаметкиНаПолях #AsyncAwaitFAQ
Самые Частые Ошибки при Работе с async/await. Продолжение 5-7
Начало
5. Не ожидать Task в выражении using
❌ Неверно
Если мы пропустим ключевое слово
❌ Неверно
Отсутствие ключевого слова await перед асинхронной операцией приведет к завершению метода до завершения данной асинхронной операции. Метод будет вести себя непредсказуемо, и результат будет отличаться от ожиданий. Ещё хуже, если неожидаемое выражение выбросит исключение. Оно остается незамеченным и не вызовет сбоя процесса, что ещё больше затруднит его обнаружение. Вы всегда должны ожидать асинхронное выражение или присвоить возвращаемую задачу переменной и убедиться, что в итоге она где-то ожидается.
❌ Неверно
Источник: https://cezarypiatek.github.io/post/async-analyzers-p1/
Самые Частые Ошибки при Работе с async/await. Продолжение 5-7
Начало
5. Не ожидать Task в выражении using
System.Threading.Tasks.Task
реализует интерфейс IDisposable
. Вызов метода, возвращающего Task
, непосредственно в выражении using приводит к удалению задачи в конце блока using
, что никогда не является ожидаемым поведением.❌ Неверно
using (CreateDisposableAsync()) {✅ Верно
…
}
using (await CreateDisposableAsync()) {6. Не ожидать Task в блоке using
…
}
Если мы пропустим ключевое слово
await
для асинхронной операции внутри блока using
, то объект может быть удалён до завершения асинхронного вызова. Это приведёт к неправильному поведению и очень часто заканчивается исключением времени выполнения, сообщающим о том, что мы пытаемся работать с уже удалённым объектом.❌ Неверно
private Task<int> DoSomething() {✅ Верно
using (var service = CreateService()) {
return service.GetAsync();
}
}
private async Task<int> DoSomething() {7. Не ожидать результата асинхронного метода
using (var service = CreateService()) {
return await service.GetAsync();
}
}
Отсутствие ключевого слова await перед асинхронной операцией приведет к завершению метода до завершения данной асинхронной операции. Метод будет вести себя непредсказуемо, и результат будет отличаться от ожиданий. Ещё хуже, если неожидаемое выражение выбросит исключение. Оно остается незамеченным и не вызовет сбоя процесса, что ещё больше затруднит его обнаружение. Вы всегда должны ожидать асинхронное выражение или присвоить возвращаемую задачу переменной и убедиться, что в итоге она где-то ожидается.
❌ Неверно
async Task DoSomethingAsync() {✅ Верно
await DoSomethingAsync1();
DoSomethingAsync2();
await DoSomethingAsync3();
}
async Task DoSomethingAsync() {Продолжение следует…
await DoSomethingAsync1();
await DoSomethingAsync2();
await DoSomethingAsync3();
}
Источник: https://cezarypiatek.github.io/post/async-analyzers-p1/
День шестьсот тридцатый. #ЗаметкиНаПолях #AsyncAwaitFAQ
Самые Частые Ошибки при Работе с async/await. Продолжение 8-10
Начало
Часть 2
8. Синхронные ожидания
Если вы хотите ожидать асинхронное выражение в синхронном методе, вы должны переписать всю цепочку вызовов на асинхронную. Кажется, что более легкое решение - вызвать
❌ Неверно
По умолчанию, когда мы ожидаем асинхронную операцию, продолжение планируется с использованием захваченного
❌ Неверно
Возврат
❌ Неверно
Источник: https://cezarypiatek.github.io/post/async-analyzers-p2/
Самые Частые Ошибки при Работе с async/await. Продолжение 8-10
Начало
Часть 2
8. Синхронные ожидания
Если вы хотите ожидать асинхронное выражение в синхронном методе, вы должны переписать всю цепочку вызовов на асинхронную. Кажется, что более легкое решение - вызвать
Wait
или Result
для возвращаемой задачи. Но это будет стоить вам заблокированного потока и может привести к взаимной блокировке. Сделайте всю цепочку асинхронной. В консольном приложении допустим асинхронный метод Main, в контроллерах ASP.NET – асинхронные методы действия.❌ Неверно
void DoSomething() {✅ Верно
Thread.Sleep(1);
Task.Delay(2).Wait();
var result1 = GetAsync().Result;
var result2 = GetAsync().GetAwaiter().
GetResult();
var unAwaitedResult3 = GetAsync();
var result3 = unAwaitedResult3.Result;
}
async Task DoSomething() {9. Отсутствие ConfigureAwait(bool)
await Task.Delay(1);
await Task.Delay(2);
var result1 = await GetAsync();
var result2 = await GetAsync();
}
По умолчанию, когда мы ожидаем асинхронную операцию, продолжение планируется с использованием захваченного
SynchronizationContext
или TaskScheduler
. Это приводит к дополнительным затратам и может привести к взаимной блокировке, особенно в WindowsForms, WPF и старых приложениях ASP.NET. Вызывая ConfigureAwait(false)
, мы гарантируем, что текущий контекст игнорируется при вызове продолжения. Подробнее о ConfigureAwait
в серии постов с тегом #AsyncAwaitFAQ❌ Неверно
async Task DoSomethingAsync() {✅ Верно
await DoSomethingElse();
}
async Task DoSomethingAsync() {10. Возврат null из метода, возвращающего Task
await DoSomethingElse().
ConfigureAwait(false);
}
Возврат
null
значения из синхронного метода типа Task
/Task<>
приводит к исключению NullReferenceException
, если кто-то ожидает этот метод. Чтобы этого избежать, всегда возвращайте результат этого метода с помощью помощников Task.CompletedTask
или Task.FromResult<T>(null)
.❌ Неверно
Task DoAsync() {✅ Верно
return null;
}
Task<object> GetSomethingAsync() {
return null;
}
Task<HttpResponseMessage>
TryGetAsync(HttpClient httpClient) {
return httpClient?.
GetAsync("/some/endpoint");
}
Task DoAsync() {Продолжение следует…
return Task.CompletedTask;
}
Task<object> GetSomethingAsync() {
return Task.FromResult<object>(null);
}
Task<HttpResponseMessage>
TryGetAsync(HttpClient httpClient) {
return httpClient?.
GetAsync("/some/endpoint") ??
Task.FromResult(default(
HttpResponseMessage));
}
Источник: https://cezarypiatek.github.io/post/async-analyzers-p2/
День шестьсот тридцать первый. #ЗаметкиНаПолях #AsyncAwaitFAQ
Самые Частые Ошибки при Работе с async/await. Продолжение 11-13
Начало
Часть 2
Часть 3
11. Передача токена отмены
Если вы забудете передать токен отмены, это может привести к большим проблемам. Запущенная длительная операция без токена отмены может заблокировать действие по остановке приложения или привести к нехватке потоков при большом количестве отменённых веб-запросов. Чтобы избежать этого, всегда создавайте и передавайте токен отмены методам, которые его принимают, даже если это необязательный параметр.
❌ Неверно
Эта ошибка похожа на предыдущую, но относится исключительно к
❌ Неверно
И наоборот, имена синхронных методов не должны заканчиваться на
❌ Неверно
Источник: https://cezarypiatek.github.io/post/async-analyzers-p2/
Самые Частые Ошибки при Работе с async/await. Продолжение 11-13
Начало
Часть 2
Часть 3
11. Передача токена отмены
Если вы забудете передать токен отмены, это может привести к большим проблемам. Запущенная длительная операция без токена отмены может заблокировать действие по остановке приложения или привести к нехватке потоков при большом количестве отменённых веб-запросов. Чтобы избежать этого, всегда создавайте и передавайте токен отмены методам, которые его принимают, даже если это необязательный параметр.
❌ Неверно
public async Task<string>✅ Верно
GetSomething(HttpClient http) {
var response = await
http.GetAsync(new Uri("/endpoint/"));
return await
response.Content.ReadAsStringAsync();
}
public async Task<string>12. Использование токена отмены с IAsyncEnumerable
GetSomething(HttpClient http,
CancellationToken ct) {
var response = await
http.GetAsync(new Uri("/endpoint/"),
ct);
return await
response.Content.ReadAsStringAsync();
}
Эта ошибка похожа на предыдущую, но относится исключительно к
IAsyncEnumerable
и её довольно легко допустить. Это может быть неочевидно, но передача токена отмены в асинхронный перечислитель выполняется путем вызова метода WithCancellation()
.❌ Неверно
async Task Iterate(✅ Верно
IAsyncEnumerable<string> e) {
await foreach (var item in e) {
…
}
}
async Task Iterate(13. Имена асинхронных методов должны заканчиваться на Async
IAsyncEnumerable<string> e,
CancellationToken ct) {
await foreach (var item in
e.WithCancellation(ct))
{
…
}
}
И наоборот, имена синхронных методов не должны заканчиваться на
Async
. Так обычно происходит при невнимательном рефакторинге. Это не строгое обязательство и не ошибка. Вообще, это соглашение об именовании имеет смысл только тогда, когда класс предоставляет как синхронные, так и асинхронные версии метода.❌ Неверно
async Task DoSomething() {✅ Верно
await Task.Yield();
}
async Task DoSomethingAsync() {Продолжение следует…
await Task.Yield();
}
Источник: https://cezarypiatek.github.io/post/async-analyzers-p2/
День шестьсот тридцать второй. #ЗаметкиНаПолях #AsyncAwaitFAQ
Самые Частые Ошибки при Работе с async/await. Продолжение 14-16
Начало
Часть 2
Часть 3
Часть 4
14. Злоупотребление Task.Run в простых случаях
Для предварительно вычисленных или легко вычисляемых результатов нет необходимости вызывать
❌ Неверно
Хотя методы продолжений по-прежнему можно использовать, обычно рекомендуется использовать async/await вместо
❌ Неверно
Конструкторы синхронны. Если вам нужно инициализировать некоторую логику, которая может быть асинхронной, использование
Источник: https://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/AsyncGuidance.md
Самые Частые Ошибки при Работе с async/await. Продолжение 14-16
Начало
Часть 2
Часть 3
Часть 4
14. Злоупотребление Task.Run в простых случаях
Для предварительно вычисленных или легко вычисляемых результатов нет необходимости вызывать
Task.Run
, который поставит задачу в очередь пула потоков, а задача немедленно завершится. Вместо этого используйте Task.FromResult
, чтобы создать задачу, обёртывающую уже вычисленный результат.❌ Неверно
public Task<int> AddAsync(int a, int b) {✅ Верно
return Task.Run(() => a + b);
}
public Task<int> AddAsync(int a, int b) {15. Await лучше, чем ContinueWith
return Task.FromResult(a + b);
}
Хотя методы продолжений по-прежнему можно использовать, обычно рекомендуется использовать async/await вместо
ContinueWith
. Кроме того, надо отметить, что ContinueWith
не захватывает SynchronizationContext
и поэтому семантически отличается от async/await.❌ Неверно
public Task<int> DoSomethingAsync() {✅ Верно
return CallDependencyAsync()
.ContinueWith(task => {
return task.Result + 1;
});
}
public async Task<int> DoSomethingAsync() {16. Синхронизация асинхронного кода в конструкторах
var result =
await CallDependencyAsync();
return result + 1;
}
Конструкторы синхронны. Если вам нужно инициализировать некоторую логику, которая может быть асинхронной, использование
Task.Result
для синхронизации в конструкторе может привести к истощению пула потоков и взаимным блокировкам. Лучше использовать статическую фабрику.public interface IRemoteConnFactory {❌ Неверно
Task<IRemoteConn> ConnectAsync();
}
public interface IRemoteConn { … }
public class Service : IService {✅ Верно
private readonly IRemoteConn _conn;
public Service(IRemoteConnFactory cf) {
_conn = cf.ConnectAsync().Result;
}
}
public class Service : IService {Окончание следует…
private readonly IRemoteConn _conn;
private Service(IRemoteConn conn) {
_conn = conn;
}
public static async Task<Service>
CreateAsync(IRemoteConnFactory cf)
{
return new Service(
await cf.ConnectAsync());
}
}
…
var cf = new ConnFactory();
var srv = await Service.CreateAsync(cf);
Источник: https://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/AsyncGuidance.md
День шестьсот тридцать третий. #ЗаметкиНаПолях #AsyncAwaitFAQ
Анализаторы кода для асинхронного программирования
Большинство ошибок, описанных в предыдущих постах, можно обнаружить с помощью анализаторов кода, представленных в следующих пакетах. Многие из них не ограничены поиском ошибок в асинхронном коде, поэтому для каждого приведены правила, проверяющие перечисленные ранее ошибки.
1. Microsoft.CodeAnalysis.FxCopAnalyzers
CA2007 - Consider calling ConfigureAwait on the awaited task
CA2008 - Do not create tasks without passing a TaskScheduler
Полный список правил
2. Microsoft.VisualStudio.Threading.Analyzers
VSTHRD002 - Avoid problematic synchronous waits
VSTHRD100 - Avoid async void methods
VSTHRD101 - Avoid unsupported async delegates
VSTHRD107 - Await Task within using expression
VSTHRD111 - Use .ConfigureAwait(bool)
VSTHRD112 - Implement System.IAsyncDisposable
VSTHRD114 - Avoid returning null from a Task-returning method
VSTHRD200 - Use Async naming convention
Полный список правил
3. AsyncFixer
AsyncFixer01 - Unnecessary async/await usage
AsyncFixer03 - Fire & forget async void methods
AsyncFixer04 - Fire & forget async call inside a using block
Полный список правил
4. Roslyn.Analyzers
ASYNC0001 - Asynchronous method names should end with Async
ASYNC0002 - Non asynchronous method names shouldn’t end with Async
ASYNC0003 - Avoid void returning asynchronous method
ASYNC0004 - Use ConfigureAwait(false) on await expression
Полный список правил
5. Meziantou.Analyzer
MA0004 - Use .ConfigureAwait(false)
MA0022 - Return Task.FromResult instead of returning null
MA0032 - Use an overload that have cancellation token
MA0040 - Flow the cancellation token when available
MA0045 - Do not use blocking call (make method async)
MA0079 - Flow a cancellation token using .WithCancellation()
MA0080 - Specify a cancellation token using .WithCancellation()
Полный список правил
6. Roslynator
RCS1046 - Asynchronous method name should end with Async
RCS1047 - Non-asynchronous method name should not end with Async
RCS1090 - Call ConfigureAwait(false)
RCS1174 - Remove redundant async/await
RCS1210 - Return Task.FromResult instead of returning null
RCS1229 - Use async/await when necessary
Полный список правил
7. Asyncify
AsyncifyInvocation - This invocation could benefit from the use of Task async
AsyncifyVariable - This variable access could benefit from the use of Task async
Источник: https://cezarypiatek.github.io/post/async-analyzers-p1/
Анализаторы кода для асинхронного программирования
Большинство ошибок, описанных в предыдущих постах, можно обнаружить с помощью анализаторов кода, представленных в следующих пакетах. Многие из них не ограничены поиском ошибок в асинхронном коде, поэтому для каждого приведены правила, проверяющие перечисленные ранее ошибки.
1. Microsoft.CodeAnalysis.FxCopAnalyzers
CA2007 - Consider calling ConfigureAwait on the awaited task
CA2008 - Do not create tasks without passing a TaskScheduler
Полный список правил
2. Microsoft.VisualStudio.Threading.Analyzers
VSTHRD002 - Avoid problematic synchronous waits
VSTHRD100 - Avoid async void methods
VSTHRD101 - Avoid unsupported async delegates
VSTHRD107 - Await Task within using expression
VSTHRD111 - Use .ConfigureAwait(bool)
VSTHRD112 - Implement System.IAsyncDisposable
VSTHRD114 - Avoid returning null from a Task-returning method
VSTHRD200 - Use Async naming convention
Полный список правил
3. AsyncFixer
AsyncFixer01 - Unnecessary async/await usage
AsyncFixer03 - Fire & forget async void methods
AsyncFixer04 - Fire & forget async call inside a using block
Полный список правил
4. Roslyn.Analyzers
ASYNC0001 - Asynchronous method names should end with Async
ASYNC0002 - Non asynchronous method names shouldn’t end with Async
ASYNC0003 - Avoid void returning asynchronous method
ASYNC0004 - Use ConfigureAwait(false) on await expression
Полный список правил
5. Meziantou.Analyzer
MA0004 - Use .ConfigureAwait(false)
MA0022 - Return Task.FromResult instead of returning null
MA0032 - Use an overload that have cancellation token
MA0040 - Flow the cancellation token when available
MA0045 - Do not use blocking call (make method async)
MA0079 - Flow a cancellation token using .WithCancellation()
MA0080 - Specify a cancellation token using .WithCancellation()
Полный список правил
6. Roslynator
RCS1046 - Asynchronous method name should end with Async
RCS1047 - Non-asynchronous method name should not end with Async
RCS1090 - Call ConfigureAwait(false)
RCS1174 - Remove redundant async/await
RCS1210 - Return Task.FromResult instead of returning null
RCS1229 - Use async/await when necessary
Полный список правил
7. Asyncify
AsyncifyInvocation - This invocation could benefit from the use of Task async
AsyncifyVariable - This variable access could benefit from the use of Task async
Источник: https://cezarypiatek.github.io/post/async-analyzers-p1/
День шестьсот тридцать четвёртый. #Оффтоп
В прошлое воскресенье мы с вами говорили о повышении, сегодня наоборот, поговорим о том, чего не стоит делать, чтобы не пришлось обновлять резюме. Поводом послужило видео от Сергея Немчинского (ссылка ниже). Здесь опишу суть с краткими комментариями.
Опустим причины, которые вас не касаются, вроде закрытия компании, отдела, сокращения штата и т.д., и т.п. Обсудим только то, что зависит от вас.
Нанимать нового программиста дорого, поэтому просто так, без веских причин, вас вряд ли «попросят». Скорее неугодного человека переведут на малозначимую, скучную работу, которую кто-то должен делать, но тратить время хороших специалистов на неё жалко. Поэтому, если вы обнаружили себя на таком месте, есть повод задуматься.
Пять причин увольнения программистов
1. Ложь
Это, по-моему, самая веская причина увольнения программистов. В нашей сфере очень много построено на доверии, поэтому если человека ловят на обмане, работать с ним будет невозможно. Моего коллегу уволили ровно за это. Работали удалённо, с ним несколько раз за день пытались связаться, он не отвечал, а потом написал, что работал все 8 часов в этот день. Это, как говорят у них, "a big no-no".
2. Софт скилы
Как обычно, всё решают человеческие отношения. Неумение взаимодействовать с коллегами и руководством, токсичность, неумение отстоять свои идеи, и т.д. Если с вами по-человечески неприятно работать, вас либо задвинут на нудную работу, либо, в худшем случае, с вами попрощаются.
3. Несоответствие ожиданиям
Это скорее ошибка найма, когда принимают человека, явно не соответствующего требуемой квалификации, или когда хотят, чтобы новенький работал точно так же, как его предшественник. Тут не будет вашей вины, если только не… см. пункт 1. Если вы при найме сказали, что в совершенстве владеете тем, о чём понятия не имеете, уж не обессудьте.
4. Нарушение NDA
Ещё одна из вариаций лжи. Вы соглашаетесь с неразглашением информации, подписываете документ, а потом нарушаете договор. Учтите, что особенно в западных компаниях к этому относятся очень серьёзно.
5. Хард скилы
Здесь проблема скорее не в как таковом незнании чего-то, а в неумении или нежелании научиться этому. Но всё-таки, в нашей профессии это встречается довольно редко.
Подробности по ссылке ниже. Давайте обсудим. За что увольняливас… нет, конечно, не вас, ваших коллег или знакомых?
Источник: https://www.youtube.com/watch?v=QUr4NS-UQK4
В прошлое воскресенье мы с вами говорили о повышении, сегодня наоборот, поговорим о том, чего не стоит делать, чтобы не пришлось обновлять резюме. Поводом послужило видео от Сергея Немчинского (ссылка ниже). Здесь опишу суть с краткими комментариями.
Опустим причины, которые вас не касаются, вроде закрытия компании, отдела, сокращения штата и т.д., и т.п. Обсудим только то, что зависит от вас.
Нанимать нового программиста дорого, поэтому просто так, без веских причин, вас вряд ли «попросят». Скорее неугодного человека переведут на малозначимую, скучную работу, которую кто-то должен делать, но тратить время хороших специалистов на неё жалко. Поэтому, если вы обнаружили себя на таком месте, есть повод задуматься.
Пять причин увольнения программистов
1. Ложь
Это, по-моему, самая веская причина увольнения программистов. В нашей сфере очень много построено на доверии, поэтому если человека ловят на обмане, работать с ним будет невозможно. Моего коллегу уволили ровно за это. Работали удалённо, с ним несколько раз за день пытались связаться, он не отвечал, а потом написал, что работал все 8 часов в этот день. Это, как говорят у них, "a big no-no".
2. Софт скилы
Как обычно, всё решают человеческие отношения. Неумение взаимодействовать с коллегами и руководством, токсичность, неумение отстоять свои идеи, и т.д. Если с вами по-человечески неприятно работать, вас либо задвинут на нудную работу, либо, в худшем случае, с вами попрощаются.
3. Несоответствие ожиданиям
Это скорее ошибка найма, когда принимают человека, явно не соответствующего требуемой квалификации, или когда хотят, чтобы новенький работал точно так же, как его предшественник. Тут не будет вашей вины, если только не… см. пункт 1. Если вы при найме сказали, что в совершенстве владеете тем, о чём понятия не имеете, уж не обессудьте.
4. Нарушение NDA
Ещё одна из вариаций лжи. Вы соглашаетесь с неразглашением информации, подписываете документ, а потом нарушаете договор. Учтите, что особенно в западных компаниях к этому относятся очень серьёзно.
5. Хард скилы
Здесь проблема скорее не в как таковом незнании чего-то, а в неумении или нежелании научиться этому. Но всё-таки, в нашей профессии это встречается довольно редко.
Подробности по ссылке ниже. Давайте обсудим. За что увольняли
Источник: https://www.youtube.com/watch?v=QUr4NS-UQK4
День шестьсот тридцать пятый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
64. Предотвращайте Ошибки
Сообщения об ошибках - наиболее важные взаимодействия между пользователем и системой. Легко представить ошибку, вызванную неправильным вводом данных пользователем. Но люди систематически совершают вполне предсказуемые виды ошибок. Поэтому можно «отладить» связь между пользователем и системой так же, как и между компонентами системы.
Предположим, вы хотите, чтобы пользователь ввёл дату в допустимом диапазоне. Вместо того, чтобы позволять пользователю вводить любую дату, лучше предложить компонент UI вроде списка или календаря, предлагающего только разрешённые даты. Тогда ввести неверную дату будет невозможно.
Ошибки форматирования - ещё одна распространённая проблема. Например, пользователю предоставляется текстовое поле для ввода даты, и он вводит «
Такие ошибки возникают из-за того, что легче отклонить дату, чем проанализировать три или четыре наиболее распространённых формата даты и приводить их к нужному формату в программе. Подобные мелкие «недочёты» раздражают пользователя, что, в свою очередь, приводит к новым ошибкам, поскольку пользователь теряет концентрацию. Уважайте желание пользователей вводить информацию, а не данные.
Другой способ избежать ошибок форматирования - добавить подсказки. Например, с помощью метки в поле, показывающей желаемый формат («
Есть два способа сообщить пользователю, как правильно ввести информацию: инструкции и подсказки. Подсказки кратки и отображаются в точке ввода информации, инструкции более подробны и обычно располагаются перед формой.
Как правило, инструкции не помогают предотвратить ошибку. Пользователи склонны предполагать, что интерфейс будет работать в соответствии с их прошлым опытом («Конечно, все знают, что означает «26.10.2020»). Так что инструкции остаются непрочитанными. Подсказки более полезны в предотвращении ошибок.
Другой способ избежать ошибок - предложить значения по умолчанию. Например, пользователи обычно вводят значения даты, соответствующие сегодняшнему дню, завтрашнему дню, их дню рождения, ранее введённой дате и т.п. В зависимости от контекста одно из этих значений, вероятно, будет хорошим выбором по умолчанию.
Какой бы ни была причина, системы должны снисходительно относиться к ошибкам пользователей. Помимо описанного выше, можно предоставить пользователю несколько уровней отмены действий, особенно тех, которые могут уничтожить или изменить данные пользователя.
Регистрация и анализ действий отмены также может выявить, где интерфейс провоцирует пользователей на ошибки, вроде постоянных нажатий «неправильной» кнопки. Эти ошибки часто возникают из-за вводящих в заблуждение подсказок или последовательности действий, которую можно изменить, чтобы предотвратить такие ошибки в дальнейшем.
Какой бы подход вы ни выбрали, большинство ошибок носит систематический характер, это результат недопонимания между пользователем и программой. Понимание того, как пользователи думают, интерпретируют информацию, принимают решения и вводят данные, поможет вам отладить взаимодействие между вашей программой и вашими пользователями.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Giles Colborne
97 Вещей, Которые Должен Знать Каждый Программист
64. Предотвращайте Ошибки
Сообщения об ошибках - наиболее важные взаимодействия между пользователем и системой. Легко представить ошибку, вызванную неправильным вводом данных пользователем. Но люди систематически совершают вполне предсказуемые виды ошибок. Поэтому можно «отладить» связь между пользователем и системой так же, как и между компонентами системы.
Предположим, вы хотите, чтобы пользователь ввёл дату в допустимом диапазоне. Вместо того, чтобы позволять пользователю вводить любую дату, лучше предложить компонент UI вроде списка или календаря, предлагающего только разрешённые даты. Тогда ввести неверную дату будет невозможно.
Ошибки форматирования - ещё одна распространённая проблема. Например, пользователю предоставляется текстовое поле для ввода даты, и он вводит «
26.10.2020
». Неразумно отклонять её просто потому, что она имеет другой формат (например, вместо нужного «ДД/ММ/ГГГГ
»). Ещё хуже отклонить «26 / 10 / 2020
», потому что дата содержит лишние пробелы. Пользователю сложно будет понять, в чём ошибка, т.к. дата представлена в нужном формате.Такие ошибки возникают из-за того, что легче отклонить дату, чем проанализировать три или четыре наиболее распространённых формата даты и приводить их к нужному формату в программе. Подобные мелкие «недочёты» раздражают пользователя, что, в свою очередь, приводит к новым ошибкам, поскольку пользователь теряет концентрацию. Уважайте желание пользователей вводить информацию, а не данные.
Другой способ избежать ошибок форматирования - добавить подсказки. Например, с помощью метки в поле, показывающей желаемый формат («
ДД/ММ/ГГГГ
») или разделив поле на три цифровых по два, два и четыре символа.Есть два способа сообщить пользователю, как правильно ввести информацию: инструкции и подсказки. Подсказки кратки и отображаются в точке ввода информации, инструкции более подробны и обычно располагаются перед формой.
Как правило, инструкции не помогают предотвратить ошибку. Пользователи склонны предполагать, что интерфейс будет работать в соответствии с их прошлым опытом («Конечно, все знают, что означает «26.10.2020»). Так что инструкции остаются непрочитанными. Подсказки более полезны в предотвращении ошибок.
Другой способ избежать ошибок - предложить значения по умолчанию. Например, пользователи обычно вводят значения даты, соответствующие сегодняшнему дню, завтрашнему дню, их дню рождения, ранее введённой дате и т.п. В зависимости от контекста одно из этих значений, вероятно, будет хорошим выбором по умолчанию.
Какой бы ни была причина, системы должны снисходительно относиться к ошибкам пользователей. Помимо описанного выше, можно предоставить пользователю несколько уровней отмены действий, особенно тех, которые могут уничтожить или изменить данные пользователя.
Регистрация и анализ действий отмены также может выявить, где интерфейс провоцирует пользователей на ошибки, вроде постоянных нажатий «неправильной» кнопки. Эти ошибки часто возникают из-за вводящих в заблуждение подсказок или последовательности действий, которую можно изменить, чтобы предотвратить такие ошибки в дальнейшем.
Какой бы подход вы ни выбрали, большинство ошибок носит систематический характер, это результат недопонимания между пользователем и программой. Понимание того, как пользователи думают, интерпретируют информацию, принимают решения и вводят данные, поможет вам отладить взаимодействие между вашей программой и вашими пользователями.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Giles Colborne
👍1
День шестьсот тридцать шестой. #BestPractices #IDEALS
Принципы Разработки Микросервисов: IDEALS вместо SOLID. 1/7
В 2000 году Роберт Мартин составил пять принципов объектно-ориентированного проектирования, которые Майкл Фезерс позднее объединил в аббревиатуру SOLID. С тех пор принципы SOLID для объектно-ориентированного проектирования были неоднократно описаны в книгах и стали широко известны в отрасли.
Применимы ли принципы SOLID к микросервисам? Отчасти.
Мы, как отрасль, разрабатываем и внедряем решения на основе микросервисов уже более шести лет. За это время постоянно увеличивающееся количество инструментов, фреймворков, платформ и вспомогательных продуктов создали невероятно богатый технологический ландшафт вокруг микросервисов.
Такой ландшафт может вызвать головокружение у начинающих разработчиков микросервисов из-за множества дизайнерских и технологических решений, с которыми они могут столкнуться. И в этом случае базовый набор принципов может помочь разработчикам выбрать правильные проектные решения.
Хотя некоторые принципы SOLID применимы к микросервисам, объектная ориентация - это парадигма дизайна на уровне элементов (классов, интерфейсов, иерархий и т.д.), которые принципиально отличаются от элементов в распределённых системах в целом и микросервисах в частности.
Рассмотрим следующий набор основных принципов проектирования микросервисов:
I - Разделение интерфейсов
D - Легкость развёртывания
E – Ориентированность на события
A - Доступность важнее согласованности
L - Слабая связанность
S - Единственная ответственность
Эти принципы не охватывают весь спектр проектных решений для микросервисов, но они затрагивают ключевые проблемы и факторы успеха для создания современных систем на основе сервисов.
Продолжение следует…
Источник: https://www.infoq.com/articles/microservices-design-ideals/
Принципы Разработки Микросервисов: IDEALS вместо SOLID. 1/7
В 2000 году Роберт Мартин составил пять принципов объектно-ориентированного проектирования, которые Майкл Фезерс позднее объединил в аббревиатуру SOLID. С тех пор принципы SOLID для объектно-ориентированного проектирования были неоднократно описаны в книгах и стали широко известны в отрасли.
Применимы ли принципы SOLID к микросервисам? Отчасти.
Мы, как отрасль, разрабатываем и внедряем решения на основе микросервисов уже более шести лет. За это время постоянно увеличивающееся количество инструментов, фреймворков, платформ и вспомогательных продуктов создали невероятно богатый технологический ландшафт вокруг микросервисов.
Такой ландшафт может вызвать головокружение у начинающих разработчиков микросервисов из-за множества дизайнерских и технологических решений, с которыми они могут столкнуться. И в этом случае базовый набор принципов может помочь разработчикам выбрать правильные проектные решения.
Хотя некоторые принципы SOLID применимы к микросервисам, объектная ориентация - это парадигма дизайна на уровне элементов (классов, интерфейсов, иерархий и т.д.), которые принципиально отличаются от элементов в распределённых системах в целом и микросервисах в частности.
Рассмотрим следующий набор основных принципов проектирования микросервисов:
I - Разделение интерфейсов
D - Легкость развёртывания
E – Ориентированность на события
A - Доступность важнее согласованности
L - Слабая связанность
S - Единственная ответственность
Эти принципы не охватывают весь спектр проектных решений для микросервисов, но они затрагивают ключевые проблемы и факторы успеха для создания современных систем на основе сервисов.
Продолжение следует…
Источник: https://www.infoq.com/articles/microservices-design-ideals/
День шестьсот тридцать седьмой. #BestPractices #IDEALS
Принципы Разработки Микросервисов: IDEALS вместо SOLID. 2/7
I – Разделение Интерфейсов (Interface Segregation)
Исходный принцип разделения интерфейсов предостерегает от использования в ООП «жирных» интерфейсов. Другими словами, вместо интерфейса со всеми возможными методами, которые могут понадобиться клиентам, должны быть отдельные интерфейсы, обслуживающие конкретные потребности каждого типа клиентов.
Стиль микросервисной архитектуры - это специализация сервисно-ориентированной архитектуры (SOA), в которой дизайн интерфейсов (то есть контрактов сервисов) всегда имел первостепенное значение. С начала 2000-х, литература по SOA предписывала использовать канонические модели или канонические схемы, которым должны соответствовать все клиенты сервисов. Однако наш подход к разработке контрактов на обслуживание изменился со времен SOA. В эпоху микросервисов часто существует множество клиентских программ (фронтендов) для одной логики сервиса. Это основная мотивация применения принципа разделения интерфейсов к микросервисам.
Реализация разделения интерфейсов для микросервисов
Цель разделения интерфейсов для микросервисов состоит в том, чтобы каждый тип фронтенда получал контракт на обслуживание, который наилучшим образом соответствует его потребностям. Например: мобильное приложение хочет вызвать конечные точки, которые отвечают кратким представлением данных в формате JSON. Веб-приложение в той же системе использует полное представление объектов в JSON. Старое настольное приложение, которое вызывает ту же службу, требует полного представления, но в XML. Разные клиенты также могут использовать разные протоколы. Например, внешние клиенты могут использовать HTTP для вызова сервиса gRPC.
Вместо того, чтобы пытаться навязать один и тот же контракт (с использованием канонических моделей) для всех типов клиентов сервиса, мы «разделяем интерфейс», чтобы каждый тип клиента видел интерфейс сервиса, который ему нужен. Как это сделать? Отличным вариантом является использование шлюза API. Он может выполнять преобразование формата и структуры сообщений, преобразование протоколов, маршрутизацию сообщений и многое другое. Популярной альтернативой является шаблон Backend for Frontend (BFF). В этом случае у нас есть шлюз API для каждого типа клиента или разные BFF для каждого клиента, как показано на рисунке ниже.
Продолжение следует…
Источник: https://www.infoq.com/articles/microservices-design-ideals/
Принципы Разработки Микросервисов: IDEALS вместо SOLID. 2/7
I – Разделение Интерфейсов (Interface Segregation)
Исходный принцип разделения интерфейсов предостерегает от использования в ООП «жирных» интерфейсов. Другими словами, вместо интерфейса со всеми возможными методами, которые могут понадобиться клиентам, должны быть отдельные интерфейсы, обслуживающие конкретные потребности каждого типа клиентов.
Стиль микросервисной архитектуры - это специализация сервисно-ориентированной архитектуры (SOA), в которой дизайн интерфейсов (то есть контрактов сервисов) всегда имел первостепенное значение. С начала 2000-х, литература по SOA предписывала использовать канонические модели или канонические схемы, которым должны соответствовать все клиенты сервисов. Однако наш подход к разработке контрактов на обслуживание изменился со времен SOA. В эпоху микросервисов часто существует множество клиентских программ (фронтендов) для одной логики сервиса. Это основная мотивация применения принципа разделения интерфейсов к микросервисам.
Реализация разделения интерфейсов для микросервисов
Цель разделения интерфейсов для микросервисов состоит в том, чтобы каждый тип фронтенда получал контракт на обслуживание, который наилучшим образом соответствует его потребностям. Например: мобильное приложение хочет вызвать конечные точки, которые отвечают кратким представлением данных в формате JSON. Веб-приложение в той же системе использует полное представление объектов в JSON. Старое настольное приложение, которое вызывает ту же службу, требует полного представления, но в XML. Разные клиенты также могут использовать разные протоколы. Например, внешние клиенты могут использовать HTTP для вызова сервиса gRPC.
Вместо того, чтобы пытаться навязать один и тот же контракт (с использованием канонических моделей) для всех типов клиентов сервиса, мы «разделяем интерфейс», чтобы каждый тип клиента видел интерфейс сервиса, который ему нужен. Как это сделать? Отличным вариантом является использование шлюза API. Он может выполнять преобразование формата и структуры сообщений, преобразование протоколов, маршрутизацию сообщений и многое другое. Популярной альтернативой является шаблон Backend for Frontend (BFF). В этом случае у нас есть шлюз API для каждого типа клиента или разные BFF для каждого клиента, как показано на рисунке ниже.
Продолжение следует…
Источник: https://www.infoq.com/articles/microservices-design-ideals/
День шестьсот тридцать восьмой. #BestPractices #IDEALS
Принципы Разработки Микросервисов: IDEALS вместо SOLID. 3/7
D – Легкость развёртывания (Deployability)
Как разработчики, мы давно осознаём важность правильной упаковки и развертывания ПО, но мы никогда не уделяли так много внимания развёртыванию и мониторингу во время выполнения, как при использовании микросервисов. Технологии и дизайнерские решения, используемые при развёртывании, критически важны для успеха микросервисов. Основная причина в том, что микросервисы резко увеличивают количество единиц развёртывания.
Разработчики микросервисов несут ответственность за обеспечение доступности ПО и его новых версий для пользователей. Легкость развёртывания включает:
1. Настройку инфраструктуры времени выполнения: контейнеры, модули, кластеры, хранилище, безопасность и сеть.
2. Масштабирование микросервисов или их перенос из одной среды выполнения в другую.
3. Ускорение процесса «внесение изменений > сборка > тестирование > развёртывание».
4. Минимизацию времени простоя при замене текущей версии.
5. Синхронизацию изменений версий связанного ПО.
6. Контроль состояния микросервисов для быстрого выявления и устранения неисправностей.
Автоматизация - ключ к эффективному развёртыванию. В этой области мы наблюдаем наибольшие изменения с момента появления микросервисов. Поэтому разработчики микросервисов постоянно должны искать новые инструменты и платформы, но всегда оценивать их преимущества и недостатки.
Вот список стратегий и технологий для улучшения развёртываемости микросервисов:
1. Контейнеризация: Контейнерные микросервисы намного проще реплицировать и развёртывать на различных платформах и в облаке.
2. Service mesh: этот вид инструментов может использоваться для мониторинга трафика, применения политик, аутентификации, маршрутизации, автоматического включения, преобразования сообщений и т.п.
3. Шлюз API: перехватывая вызовы микросервисов, шлюз API предоставляет широкий набор функций, включая преобразование сообщений и протоколов, мониторинг трафика, средства управления безопасностью, маршрутизацию, кэш, регулирование запросов и т.п.
4. Бессерверная архитектура: вы можете избежать значительной части сложности и эксплуатационных затрат, связанных с управлением контейнерами, развернув свои службы на бессерверной платформе, которая следует парадигме Функция как Услуга (FaaS).
5. Инструменты мониторинга: при наличии микросервисов, распределённых по вашей локальной и облачной инфраструктуре, возможность прогнозировать, обнаруживать и уведомлять о проблемах, связанных с работоспособностью системы, приобретает решающее значение.
6. Инструменты консолидации журналов: микросервисы могут увеличить количество единиц развёртывания на порядок. Нужны инструменты консолидации журналов с возможностью поиска, анализа и генерации предупреждений.
7. Инструменты трассировки: их можно использовать при создании микросервисов, а затем для создания, сбора и визуализации данных трассировки времени выполнения. Они помогают обнаружить проблемы с производительностью (а иногда даже помогают понять архитектуру).
8. DevOps: микросервисы работают лучше, когда команды разработчиков и DevOps общаются и тесно сотрудничают от настройки инфраструктуры до обработки инцидентов.
9. «Сине-зелёное развертывание» и «канареечный» выпуск: эти стратегии развёртывания допускают нулевое или почти нулевое время простоя при выпуске новой версии микросервиса с быстрым переключением в случае возникновения проблем.
10. Инфраструктура как код (IaC): обеспечивает минимальное вмешательство человека в цикл сборки-развёртывания, который становится более быстрым, менее подверженным ошибкам и более контролируемым.
11. Непрерывная доставка: практика сокращения интервала от внесения изменений до развёртывания при сохранении качества решений.
12. Внешняя конфигурация: этот механизм позволяет сохранять свойства конфигурации вне модуля развертывания микросервиса и легко управлять ими.
Продолжение следует…
Источник: https://www.infoq.com/articles/microservices-design-ideals/
Принципы Разработки Микросервисов: IDEALS вместо SOLID. 3/7
D – Легкость развёртывания (Deployability)
Как разработчики, мы давно осознаём важность правильной упаковки и развертывания ПО, но мы никогда не уделяли так много внимания развёртыванию и мониторингу во время выполнения, как при использовании микросервисов. Технологии и дизайнерские решения, используемые при развёртывании, критически важны для успеха микросервисов. Основная причина в том, что микросервисы резко увеличивают количество единиц развёртывания.
Разработчики микросервисов несут ответственность за обеспечение доступности ПО и его новых версий для пользователей. Легкость развёртывания включает:
1. Настройку инфраструктуры времени выполнения: контейнеры, модули, кластеры, хранилище, безопасность и сеть.
2. Масштабирование микросервисов или их перенос из одной среды выполнения в другую.
3. Ускорение процесса «внесение изменений > сборка > тестирование > развёртывание».
4. Минимизацию времени простоя при замене текущей версии.
5. Синхронизацию изменений версий связанного ПО.
6. Контроль состояния микросервисов для быстрого выявления и устранения неисправностей.
Автоматизация - ключ к эффективному развёртыванию. В этой области мы наблюдаем наибольшие изменения с момента появления микросервисов. Поэтому разработчики микросервисов постоянно должны искать новые инструменты и платформы, но всегда оценивать их преимущества и недостатки.
Вот список стратегий и технологий для улучшения развёртываемости микросервисов:
1. Контейнеризация: Контейнерные микросервисы намного проще реплицировать и развёртывать на различных платформах и в облаке.
2. Service mesh: этот вид инструментов может использоваться для мониторинга трафика, применения политик, аутентификации, маршрутизации, автоматического включения, преобразования сообщений и т.п.
3. Шлюз API: перехватывая вызовы микросервисов, шлюз API предоставляет широкий набор функций, включая преобразование сообщений и протоколов, мониторинг трафика, средства управления безопасностью, маршрутизацию, кэш, регулирование запросов и т.п.
4. Бессерверная архитектура: вы можете избежать значительной части сложности и эксплуатационных затрат, связанных с управлением контейнерами, развернув свои службы на бессерверной платформе, которая следует парадигме Функция как Услуга (FaaS).
5. Инструменты мониторинга: при наличии микросервисов, распределённых по вашей локальной и облачной инфраструктуре, возможность прогнозировать, обнаруживать и уведомлять о проблемах, связанных с работоспособностью системы, приобретает решающее значение.
6. Инструменты консолидации журналов: микросервисы могут увеличить количество единиц развёртывания на порядок. Нужны инструменты консолидации журналов с возможностью поиска, анализа и генерации предупреждений.
7. Инструменты трассировки: их можно использовать при создании микросервисов, а затем для создания, сбора и визуализации данных трассировки времени выполнения. Они помогают обнаружить проблемы с производительностью (а иногда даже помогают понять архитектуру).
8. DevOps: микросервисы работают лучше, когда команды разработчиков и DevOps общаются и тесно сотрудничают от настройки инфраструктуры до обработки инцидентов.
9. «Сине-зелёное развертывание» и «канареечный» выпуск: эти стратегии развёртывания допускают нулевое или почти нулевое время простоя при выпуске новой версии микросервиса с быстрым переключением в случае возникновения проблем.
10. Инфраструктура как код (IaC): обеспечивает минимальное вмешательство человека в цикл сборки-развёртывания, который становится более быстрым, менее подверженным ошибкам и более контролируемым.
11. Непрерывная доставка: практика сокращения интервала от внесения изменений до развёртывания при сохранении качества решений.
12. Внешняя конфигурация: этот механизм позволяет сохранять свойства конфигурации вне модуля развертывания микросервиса и легко управлять ими.
Продолжение следует…
Источник: https://www.infoq.com/articles/microservices-design-ideals/
День шестьсот тридцать девятый. #BestPractices #IDEALS
Принципы Разработки Микросервисов: IDEALS вместо SOLID. 4/7
E – Ориентированность на события (Event-Driven)
Архитектура микросервисов предназначена для создания серверных сервисов, которые обычно активируются используя один из следующих вызовов:
1. HTTP-вызов (к REST сервису)
2. RPC-вызов, такой как gRPC или GraphQL
3. Асинхронное сообщение, которое проходит через очередь в диспетчере сообщений.
Первые два обычно являются синхронными, и HTTP-вызовы наиболее распространены. Часто сервисам необходимо вызывать другие сервисы, и во многих случаях это взаимодействие является синхронным. Если вместо этого мы создадим (или адаптируем) участвующие сервисы на подключение и получение сообщений из очереди, мы создадим архитектуру на основе событий.
Важным преимуществом такой архитектуры является улучшенная масштабируемость и пропускная способность. Это связано с тем, что отправители сообщений не блокируются в ожидании ответа, и одно и то же сообщение/событие могут использоваться параллельно несколькими получателями в режиме публикации-подписки.
Микросервис, управляемый событиями
Буква E в IDEALS советует нам стараться моделировать микросервисы, управляемые событиями, потому что они с большей вероятностью будут соответствовать требованиям масштабируемости и производительности современных программных решений. Такой дизайн также способствует слабой связанности, поскольку отправители и получатели сообщений - микросервисы - независимы и не знают друг о друге. Надёжность также повышается, потому что конструкция может справляться с временными отключениями микросервисов, которые позже могут обработать помещённые в очередь сообщения.
Но микросервисы, управляемые событиями, также известные как реактивные микросервисы, могут создавать проблемы. Обработка активируется асинхронно и происходит параллельно, возможно, требуя точек синхронизации и корреляции сообщений. Дизайн должен учитывать ошибки и потерянные сообщения: часто необходимы корректирующие события и механизмы отмены изменений данных. Кроме того, должен быть продуман пользовательский опыт в транзакциях, обращённых к пользователю, чтобы держать конечного пользователя в курсе о прогрессе или неудаче транзакции.
Продолжение следует…
Источник: https://www.infoq.com/articles/microservices-design-ideals/
Принципы Разработки Микросервисов: IDEALS вместо SOLID. 4/7
E – Ориентированность на события (Event-Driven)
Архитектура микросервисов предназначена для создания серверных сервисов, которые обычно активируются используя один из следующих вызовов:
1. HTTP-вызов (к REST сервису)
2. RPC-вызов, такой как gRPC или GraphQL
3. Асинхронное сообщение, которое проходит через очередь в диспетчере сообщений.
Первые два обычно являются синхронными, и HTTP-вызовы наиболее распространены. Часто сервисам необходимо вызывать другие сервисы, и во многих случаях это взаимодействие является синхронным. Если вместо этого мы создадим (или адаптируем) участвующие сервисы на подключение и получение сообщений из очереди, мы создадим архитектуру на основе событий.
Важным преимуществом такой архитектуры является улучшенная масштабируемость и пропускная способность. Это связано с тем, что отправители сообщений не блокируются в ожидании ответа, и одно и то же сообщение/событие могут использоваться параллельно несколькими получателями в режиме публикации-подписки.
Микросервис, управляемый событиями
Буква E в IDEALS советует нам стараться моделировать микросервисы, управляемые событиями, потому что они с большей вероятностью будут соответствовать требованиям масштабируемости и производительности современных программных решений. Такой дизайн также способствует слабой связанности, поскольку отправители и получатели сообщений - микросервисы - независимы и не знают друг о друге. Надёжность также повышается, потому что конструкция может справляться с временными отключениями микросервисов, которые позже могут обработать помещённые в очередь сообщения.
Но микросервисы, управляемые событиями, также известные как реактивные микросервисы, могут создавать проблемы. Обработка активируется асинхронно и происходит параллельно, возможно, требуя точек синхронизации и корреляции сообщений. Дизайн должен учитывать ошибки и потерянные сообщения: часто необходимы корректирующие события и механизмы отмены изменений данных. Кроме того, должен быть продуман пользовательский опыт в транзакциях, обращённых к пользователю, чтобы держать конечного пользователя в курсе о прогрессе или неудаче транзакции.
Продолжение следует…
Источник: https://www.infoq.com/articles/microservices-design-ideals/
День шестьсот соровокой. #BestPractices #IDEALS
Принципы Разработки Микросервисов: IDEALS вместо SOLID. 5/7
A - Доступность важнее согласованности (Availability over Consistency)
Теорема CAP, по сути, это выбор: либо согласованность, либо доступность. Обычно вам предлагается вам выбрать доступность, согласившись с уровнем согласованности. Причина проста: сегодняшние конечные пользователи не будут мириться с отсутствием доступности. Представьте себе интернет-магазин во время Чёрной пятницы. Если мы обеспечим строгую согласованность между количеством товара на складе, отображаемым при просмотре товаров, и фактическими запасами, обновляемыми при покупках, изменения данных повлекут за собой значительные накладные расходы. Если сервис обновления остатков становится временно недоступен, каталог не сможет отображать информацию о запасах, и система оформления заказов перестанет работать. Если вместо этого мы выберем доступность (принимая риск случайных несоответствий), пользователи смогут совершать покупки на основе данных о запасах, которые могут быть немного устаревшими. Одна из нескольких сотен или тысяч транзакций может закончиться тем, что неудачливый пользователь позже получит электронное письмо с извинениями за отмену покупки из-за неверной информации о запасах во время оформления заказа. Тем не менее, с точки зрения пользователя (и бизнеса) этот сценарий лучше, чем когда система недоступна или очень медленная для всех пользователей, потому что пытается обеспечить строгую согласованность.
Некоторые бизнес-операции требуют строгой последовательности. Однако, когда люди сталкиваются с выбором: как следует или прямо сейчас, они обычно выбирают «прямо сейчас».
Доступность с возможной согласованностью
Для микросервисов основной стратегией, обеспечивающей доступность, является репликация данных. Могут использоваться разные шаблоны проектирования, которые можно комбинировать:
1. Паттерн Репликации Данных Сервиса (SDR): используется, когда микросервису необходимо получить доступ к данным, принадлежащим другим приложениям (а вызовы API не подходят для получения данных). Мы создаем копию этих данных и делаем её доступной для микросервиса. При этом требуется механизм синхронизации данных, который будет периодически или на основе триггера обеспечивать согласованность копий и основных данных.
2. Паттерн Разделения Ответственности Запросов и Команд (CQRS): здесь мы отделяем разработку и реализацию операций, которые изменяют данные (команды), от операций, которые только читают данные (запросы). CQRS обычно основывается на SDR для запросов для повышения производительности и автономности.
3. Паттерн Источник Событий (Event Sourcing): вместо сохранения текущего состояния объекта в базе данных мы сохраняем неизменяемую последовательность событий, которые повлияли на этот объект. Текущее состояние получается путём воспроизведения событий. Event Sourcing обычно строится на основе CQRS.
Продолжение следует…
Источник: https://www.infoq.com/articles/microservices-design-ideals/
Принципы Разработки Микросервисов: IDEALS вместо SOLID. 5/7
A - Доступность важнее согласованности (Availability over Consistency)
Теорема CAP, по сути, это выбор: либо согласованность, либо доступность. Обычно вам предлагается вам выбрать доступность, согласившись с уровнем согласованности. Причина проста: сегодняшние конечные пользователи не будут мириться с отсутствием доступности. Представьте себе интернет-магазин во время Чёрной пятницы. Если мы обеспечим строгую согласованность между количеством товара на складе, отображаемым при просмотре товаров, и фактическими запасами, обновляемыми при покупках, изменения данных повлекут за собой значительные накладные расходы. Если сервис обновления остатков становится временно недоступен, каталог не сможет отображать информацию о запасах, и система оформления заказов перестанет работать. Если вместо этого мы выберем доступность (принимая риск случайных несоответствий), пользователи смогут совершать покупки на основе данных о запасах, которые могут быть немного устаревшими. Одна из нескольких сотен или тысяч транзакций может закончиться тем, что неудачливый пользователь позже получит электронное письмо с извинениями за отмену покупки из-за неверной информации о запасах во время оформления заказа. Тем не менее, с точки зрения пользователя (и бизнеса) этот сценарий лучше, чем когда система недоступна или очень медленная для всех пользователей, потому что пытается обеспечить строгую согласованность.
Некоторые бизнес-операции требуют строгой последовательности. Однако, когда люди сталкиваются с выбором: как следует или прямо сейчас, они обычно выбирают «прямо сейчас».
Доступность с возможной согласованностью
Для микросервисов основной стратегией, обеспечивающей доступность, является репликация данных. Могут использоваться разные шаблоны проектирования, которые можно комбинировать:
1. Паттерн Репликации Данных Сервиса (SDR): используется, когда микросервису необходимо получить доступ к данным, принадлежащим другим приложениям (а вызовы API не подходят для получения данных). Мы создаем копию этих данных и делаем её доступной для микросервиса. При этом требуется механизм синхронизации данных, который будет периодически или на основе триггера обеспечивать согласованность копий и основных данных.
2. Паттерн Разделения Ответственности Запросов и Команд (CQRS): здесь мы отделяем разработку и реализацию операций, которые изменяют данные (команды), от операций, которые только читают данные (запросы). CQRS обычно основывается на SDR для запросов для повышения производительности и автономности.
3. Паттерн Источник Событий (Event Sourcing): вместо сохранения текущего состояния объекта в базе данных мы сохраняем неизменяемую последовательность событий, которые повлияли на этот объект. Текущее состояние получается путём воспроизведения событий. Event Sourcing обычно строится на основе CQRS.
Продолжение следует…
Источник: https://www.infoq.com/articles/microservices-design-ideals/
День шестьсот сорок первый. #BestPractices #IDEALS
Принципы Разработки Микросервисов: IDEALS вместо SOLID. 6/7
L - Слабая связанность (Loose coupling)
В разработке ПО связанность означает степень взаимозависимости между двумя элементами ПО. Для систем, основанных на сервисах, связанность определяется тем, как пользователи сервиса взаимодействуют с сервисом. Мы знаем, что это взаимодействие должно осуществляться через контракт на обслуживание. Кроме того, контракт не должен быть тесно связан с деталями реализации или конкретной технологией. Сервис - это распределённый компонент, который может вызываться разными программами. Иногда хозяин сервиса даже не знает, где находятся все его пользователи (часто так бывает в случае сервисов c публичным API). Таким образом, следует избегать изменения контракта. Если сервисный контракт тесно связан с сервисной логикой или технологией, то он более подвержен изменениям, по мере развития логики или технологии.
Сервисам часто необходимо взаимодействовать с другими сервисами или другими типами компонентов, создавая таким образом эфферентную связь. Это взаимодействие устанавливает зависимости времени выполнения, которые напрямую влияют на автономность службы. Чем менее автономен сервис, тем менее предсказуемо его поведение: в лучшем случае он будет настолько быстрым, надежным и доступным, как самый медленный, наименее надёжный и наименее доступный компонент, который ему нужно вызвать.
Стратегии слабой связанности для сервисов
Буква L в IDEALS советует быть внимательными к связям сервисов и, следовательно, микросервисов. Можно использовать и комбинировать несколько стратегий, чтобы способствовать слабой связанности:
1. Точка-точка и публикация-подписка: эти стандартные шаблоны обмена сообщениями и их вариации способствуют ослаблению связанности, поскольку отправители и получатели не знают друг друга; контракт реактивного микросервиса становится именем и структурой сообщения в очереди.
2. API-шлюз и BFF: промежуточный компонент, который устраняет любые несоответствия между контрактом службы и форматом сообщения или протоколом, который клиент хочет видеть, тем самым помогая их разъединить.
3. Разработка через контракт: разрабатывая контракт независимо от любого существующего кода, мы избегаем создания API-интерфейсов, тесно связанных с технологией и реализацией.
4. Гипермедиа: для сервисов REST гипермедиа помогает интерфейсам быть более независимыми от конечных точек.
5. Паттерны Фасад и Адаптер: вариации этих шаблонов GoF в микросервисных архитектурах могут предполагать наличие внутренних компонентов или даже сервисов, которые предотвращают нежелательное связывание в реализации микросервиса.
6. База данных на каждый микросервис: микросервисы не только получают автономию, но и избегают прямого подключения к общим базам данных.
Окончание следует…
Источник: https://www.infoq.com/articles/microservices-design-ideals/
Принципы Разработки Микросервисов: IDEALS вместо SOLID. 6/7
L - Слабая связанность (Loose coupling)
В разработке ПО связанность означает степень взаимозависимости между двумя элементами ПО. Для систем, основанных на сервисах, связанность определяется тем, как пользователи сервиса взаимодействуют с сервисом. Мы знаем, что это взаимодействие должно осуществляться через контракт на обслуживание. Кроме того, контракт не должен быть тесно связан с деталями реализации или конкретной технологией. Сервис - это распределённый компонент, который может вызываться разными программами. Иногда хозяин сервиса даже не знает, где находятся все его пользователи (часто так бывает в случае сервисов c публичным API). Таким образом, следует избегать изменения контракта. Если сервисный контракт тесно связан с сервисной логикой или технологией, то он более подвержен изменениям, по мере развития логики или технологии.
Сервисам часто необходимо взаимодействовать с другими сервисами или другими типами компонентов, создавая таким образом эфферентную связь. Это взаимодействие устанавливает зависимости времени выполнения, которые напрямую влияют на автономность службы. Чем менее автономен сервис, тем менее предсказуемо его поведение: в лучшем случае он будет настолько быстрым, надежным и доступным, как самый медленный, наименее надёжный и наименее доступный компонент, который ему нужно вызвать.
Стратегии слабой связанности для сервисов
Буква L в IDEALS советует быть внимательными к связям сервисов и, следовательно, микросервисов. Можно использовать и комбинировать несколько стратегий, чтобы способствовать слабой связанности:
1. Точка-точка и публикация-подписка: эти стандартные шаблоны обмена сообщениями и их вариации способствуют ослаблению связанности, поскольку отправители и получатели не знают друг друга; контракт реактивного микросервиса становится именем и структурой сообщения в очереди.
2. API-шлюз и BFF: промежуточный компонент, который устраняет любые несоответствия между контрактом службы и форматом сообщения или протоколом, который клиент хочет видеть, тем самым помогая их разъединить.
3. Разработка через контракт: разрабатывая контракт независимо от любого существующего кода, мы избегаем создания API-интерфейсов, тесно связанных с технологией и реализацией.
4. Гипермедиа: для сервисов REST гипермедиа помогает интерфейсам быть более независимыми от конечных точек.
5. Паттерны Фасад и Адаптер: вариации этих шаблонов GoF в микросервисных архитектурах могут предполагать наличие внутренних компонентов или даже сервисов, которые предотвращают нежелательное связывание в реализации микросервиса.
6. База данных на каждый микросервис: микросервисы не только получают автономию, но и избегают прямого подключения к общим базам данных.
Окончание следует…
Источник: https://www.infoq.com/articles/microservices-design-ideals/
День шестьсот сорок второй. #BestPractices #IDEALS
Принципы Разработки Микросервисов: IDEALS вместо SOLID. 7/7
S - Единственная ответственность (Single Responsibility)
Исходный принцип единственной ответственности (SRP) - это согласованная функциональность в объектно-ориентированном классе. Наличие нескольких обязанностей в классе, естественно, влечёт тесную связанность и приводит к хрупким проектам, которые трудно развивать и которые могут неожиданно сломаться при внесении изменений. Идея проста, но, как заметил дядя Боб, SRP очень легко понять, но трудно правильно реализовать.
Понятие единственной ответственности может быть распространено на связанность сервисов. Архитектура микросервисов предполагает, что блок развёртывания должен содержать только один сервис или несколько связанных сервисов. Если микросервис наполнен обязанностями, то есть содержит слишком много не совсем связанных между собой сервисов, он может страдать от проблем монолита. Раздутый микросервис становится всё труднее развивать с точки зрения функциональности и технологического стека. Кроме того, непрерывная доставка становится обременительной, поскольку многие разработчики работают над несколькими меняющимися частями, входящими в одну единицу развёртывания.
С другой стороны, если микросервисы слишком специфичны, более вероятно, что многим из них потребуется взаимодействовать для выполнения запроса пользователя. В худшем случае изменения данных могут быть распределены по разным микросервисам, что может создать сценарий распределённой транзакции.
Правильный размер микросервисов
Важным аспектом зрелости в дизайне микросервисов является способность создавать микросервисы, которые не являются слишком большими или слишком мелкими. Выход здесь не в каком-либо инструменте или технологии, а скорее в правильном моделировании предметной области. Моделирование серверных сервисов и определение границ микросервисов для них можно выполнить разными способами. Подход, который стал популярным в отрасли для определения размера микросервисов, заключается в следовании принципам Предметно-Ориентированной Разработки (DDD):
1. Сервис (например, REST) может иметь размер агрегата DDD.
2. Микросервис может иметь размер ограниченного контекста DDD. Сервисы в этом микросервисе будут соответствовать агрегатам в этом ограниченном контексте.
3. Для взаимодействия между микросервисами мы можем использовать:
- события домена, когда асинхронный обмен сообщениями соответствует требованиям;
- вызовы API с использованием некоторой формы уровня защиты от повреждений, когда более подходит формат запрос-ответ;
- репликацию данных с поддержкой согласованности, когда микросервису требуется значительный объём данных из других доступных ограниченных контекстов.
Источник: https://www.infoq.com/articles/microservices-design-ideals/
Принципы Разработки Микросервисов: IDEALS вместо SOLID. 7/7
S - Единственная ответственность (Single Responsibility)
Исходный принцип единственной ответственности (SRP) - это согласованная функциональность в объектно-ориентированном классе. Наличие нескольких обязанностей в классе, естественно, влечёт тесную связанность и приводит к хрупким проектам, которые трудно развивать и которые могут неожиданно сломаться при внесении изменений. Идея проста, но, как заметил дядя Боб, SRP очень легко понять, но трудно правильно реализовать.
Понятие единственной ответственности может быть распространено на связанность сервисов. Архитектура микросервисов предполагает, что блок развёртывания должен содержать только один сервис или несколько связанных сервисов. Если микросервис наполнен обязанностями, то есть содержит слишком много не совсем связанных между собой сервисов, он может страдать от проблем монолита. Раздутый микросервис становится всё труднее развивать с точки зрения функциональности и технологического стека. Кроме того, непрерывная доставка становится обременительной, поскольку многие разработчики работают над несколькими меняющимися частями, входящими в одну единицу развёртывания.
С другой стороны, если микросервисы слишком специфичны, более вероятно, что многим из них потребуется взаимодействовать для выполнения запроса пользователя. В худшем случае изменения данных могут быть распределены по разным микросервисам, что может создать сценарий распределённой транзакции.
Правильный размер микросервисов
Важным аспектом зрелости в дизайне микросервисов является способность создавать микросервисы, которые не являются слишком большими или слишком мелкими. Выход здесь не в каком-либо инструменте или технологии, а скорее в правильном моделировании предметной области. Моделирование серверных сервисов и определение границ микросервисов для них можно выполнить разными способами. Подход, который стал популярным в отрасли для определения размера микросервисов, заключается в следовании принципам Предметно-Ориентированной Разработки (DDD):
1. Сервис (например, REST) может иметь размер агрегата DDD.
2. Микросервис может иметь размер ограниченного контекста DDD. Сервисы в этом микросервисе будут соответствовать агрегатам в этом ограниченном контексте.
3. Для взаимодействия между микросервисами мы можем использовать:
- события домена, когда асинхронный обмен сообщениями соответствует требованиям;
- вызовы API с использованием некоторой формы уровня защиты от повреждений, когда более подходит формат запрос-ответ;
- репликацию данных с поддержкой согласованности, когда микросервису требуется значительный объём данных из других доступных ограниченных контекстов.
Источник: https://www.infoq.com/articles/microservices-design-ideals/
День шестьсот сорок третий. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
65. Именование - это легко. Абстракция намного сложнее.
Один из наиболее распространённых мифов в разработке ПО, что именование - это сложно. Это резюмируется шутливом высказывании, приписываемом Филу Карлтону: «В программировании есть только две сложные вещи: недействительность кеша и именование объектов».
На самом деле именование не должно быть сложным. Именование - это производная от качества ваших абстракций. Если у вас есть чёткое определение обязанностей и разделение ответственности, имена обычно получаются естественным образом. В этом смысле именование - лакмусовая бумажка. Если вы ломаете голову над тем, как назвать что-то, то нужно исправлять ваши базовые абстракции.
Время, потраченное на попытки дать имя неочевидным вещам, - потерянное время.
Распространённые "запахи" именования
Есть ряд "запахов", которые могут закрасться в имена. Разработчики обычно не лингвисты, поэтому проблема чаще всего в плохом дизайне. Например, длинные имена означают, что у объекта слишком много обязанностей. Чрезмерное комментирование может быть признаком того, что название недостаточно ясно, чтобы говорить само за себя.
Нечёткие абстракции часто приводят к использованию неоднозначных существительных. Часто в монолитных приложениях Java или .Net код переплетён между неясными слоями, и возникают прекрасные
Переменные чаще всего страдают от плохого именования. Легко найти бессмысленные имена, которым не хватает точности. Десятки миллионов экземпляров «foo» на GitHub показывают, как часто разработчики поддаются соблазну не думать над именем.
Вы должны обеспечить прямую связь между именем и тем, что делает элемент. Если при чтении имя приходится «расшифровывать», имя не выполняет свою работу. Вы создали препятствие, усложняющее понимание контекста.
Постоянно контролировать имена может быть сложно. Обязанности со временем развиваются, появляются новые функции, и вы можете обнаружить, что имя больше не отражает реальность. Такой дрейф именования является самым настоящим техническим долгом, поскольку показывает, что дизайн системы не соответствовал нашему пониманию требований.
Особенно опасно использовать сокращения. Они сокращают код, но затрудняют чтение и могут быть неудобными для произношения. Что ещё более важно, постороннему человеку или новичку понадобится словарь для понимания концепций.
Следите за своим языком
Эрик Эван использовал термин ubiquitous («повсеместный») для описания общего языка, которым могут пользоваться и разработчики, и пользователи. Это было описано в контексте Предметно-Ориентированного Проектирования, при котором управление сложностью происходит путём разделения домена на автономные «ограниченные контексты», каждый со своим собственным, внутренним языком.
Это означает, что вы не можете найти единый язык для однозначного описания всей предметной области. Разделение области на части позволяет создавать более чёткие абстракции и, следовательно, более значимые имена для объектов.
Немного иронично, что термин, предназначенный для внесения ясности, нуждается в объяснении, но идея очень ценная. Создание универсального языка должно быть постоянной совместной работой в чётко определенной области. Имена должны быть обоснованы терминами, которые всем понятны. Вы должны уметь составить простой словарь, который можно будет интегрировать в повседневный ритм разработки.
Источник: https://www.ben-morris.com/naming-things-is-easy-abstraction-is-much-harder/
97 Вещей, Которые Должен Знать Каждый Программист
65. Именование - это легко. Абстракция намного сложнее.
Один из наиболее распространённых мифов в разработке ПО, что именование - это сложно. Это резюмируется шутливом высказывании, приписываемом Филу Карлтону: «В программировании есть только две сложные вещи: недействительность кеша и именование объектов».
На самом деле именование не должно быть сложным. Именование - это производная от качества ваших абстракций. Если у вас есть чёткое определение обязанностей и разделение ответственности, имена обычно получаются естественным образом. В этом смысле именование - лакмусовая бумажка. Если вы ломаете голову над тем, как назвать что-то, то нужно исправлять ваши базовые абстракции.
Время, потраченное на попытки дать имя неочевидным вещам, - потерянное время.
Распространённые "запахи" именования
Есть ряд "запахов", которые могут закрасться в имена. Разработчики обычно не лингвисты, поэтому проблема чаще всего в плохом дизайне. Например, длинные имена означают, что у объекта слишком много обязанностей. Чрезмерное комментирование может быть признаком того, что название недостаточно ясно, чтобы говорить само за себя.
Нечёткие абстракции часто приводят к использованию неоднозначных существительных. Часто в монолитных приложениях Java или .Net код переплетён между неясными слоями, и возникают прекрасные
SomethingManager
или SomethingHelper
. Обычно это свалки слабо связанной логики, поощряющие плохое планирование обязанностей.Переменные чаще всего страдают от плохого именования. Легко найти бессмысленные имена, которым не хватает точности. Десятки миллионов экземпляров «foo» на GitHub показывают, как часто разработчики поддаются соблазну не думать над именем.
Вы должны обеспечить прямую связь между именем и тем, что делает элемент. Если при чтении имя приходится «расшифровывать», имя не выполняет свою работу. Вы создали препятствие, усложняющее понимание контекста.
Постоянно контролировать имена может быть сложно. Обязанности со временем развиваются, появляются новые функции, и вы можете обнаружить, что имя больше не отражает реальность. Такой дрейф именования является самым настоящим техническим долгом, поскольку показывает, что дизайн системы не соответствовал нашему пониманию требований.
Особенно опасно использовать сокращения. Они сокращают код, но затрудняют чтение и могут быть неудобными для произношения. Что ещё более важно, постороннему человеку или новичку понадобится словарь для понимания концепций.
Следите за своим языком
Эрик Эван использовал термин ubiquitous («повсеместный») для описания общего языка, которым могут пользоваться и разработчики, и пользователи. Это было описано в контексте Предметно-Ориентированного Проектирования, при котором управление сложностью происходит путём разделения домена на автономные «ограниченные контексты», каждый со своим собственным, внутренним языком.
Это означает, что вы не можете найти единый язык для однозначного описания всей предметной области. Разделение области на части позволяет создавать более чёткие абстракции и, следовательно, более значимые имена для объектов.
Немного иронично, что термин, предназначенный для внесения ясности, нуждается в объяснении, но идея очень ценная. Создание универсального языка должно быть постоянной совместной работой в чётко определенной области. Имена должны быть обоснованы терминами, которые всем понятны. Вы должны уметь составить простой словарь, который можно будет интегрировать в повседневный ритм разработки.
Источник: https://www.ben-morris.com/naming-things-is-easy-abstraction-is-much-harder/
День шестьсот сорок четвёртый. #ЧтоНовенького #CSharp9
C# 9 Неизвестные Фишки
В C# 9 появилось много новых возможностей (см. посты по тегу #CSharp9) и несколько очень полезных малоизвестных вещей.
Инициализаторы модулей
Этот серьёзный недостаток, который до сих пор можно было исправить только некоторыми сторонними инструментами, теперь поддерживается в .NET. Инициализаторы модулей позволят библиотекам выполнять инициализацию при загрузке с минимальными накладными расходами и без необходимости явного вызова со стороны пользовательского кода. В основном это встречалось в библиотеках тестов, где вы хотите что-то инициализировать перед запуском одного, нескольких или даже всех тестов в сборке. Например, его можно использовать для переопределения некоторых статических переменных перед запуском тестирования. Чтобы использовать эту функцию, пометьте метод атрибутом
- быть статическим
- без параметров
- возвращать void
- не быть обобщённым
- не содержаться в обобщённом классе
- быть доступным из содержащего его модуля (
Для реализации проверок на null требуется много шаблонного кода и хорошая дисциплина для их последовательного применения. C# 9 решает эту проблему, предоставляя упрощённый синтаксис. Просто добавьте
Ковариантные переопределения теперь позволяют объявлять более конкретный тип при переопределении метода базового класса, содержащего менее конкретный тип возврата:
Это новая конструкция, которая позволяет объявлять
Такая возможность уже существовала с
Источник: https://blog.miguelbernard.com/c-9-the-unknown-goodies/
C# 9 Неизвестные Фишки
В C# 9 появилось много новых возможностей (см. посты по тегу #CSharp9) и несколько очень полезных малоизвестных вещей.
Инициализаторы модулей
Этот серьёзный недостаток, который до сих пор можно было исправить только некоторыми сторонними инструментами, теперь поддерживается в .NET. Инициализаторы модулей позволят библиотекам выполнять инициализацию при загрузке с минимальными накладными расходами и без необходимости явного вызова со стороны пользовательского кода. В основном это встречалось в библиотеках тестов, где вы хотите что-то инициализировать перед запуском одного, нескольких или даже всех тестов в сборке. Например, его можно использовать для переопределения некоторых статических переменных перед запуском тестирования. Чтобы использовать эту функцию, пометьте метод атрибутом
ModuleInitializer
. Не все методы могут поддерживать эту функцию. Метод должен:- быть статическим
- без параметров
- возвращать void
- не быть обобщённым
- не содержаться в обобщённом классе
- быть доступным из содержащего его модуля (
internal
или public
).[ModuleInitializer]Упрощенная проверка на null
public static void Magic() { … }
Для реализации проверок на null требуется много шаблонного кода и хорошая дисциплина для их последовательного применения. C# 9 решает эту проблему, предоставляя упрощённый синтаксис. Просто добавьте
!
в конце имени параметра метода:public void Before(string name) {Следующий метод приведёт к аналогичному сгенерированному IL-коду:
if (name is null)
throw new ArgumentNullException();
}
public void Now(string name!) { }Ковариантные Переопределения
Ковариантные переопределения теперь позволяют объявлять более конкретный тип при переопределении метода базового класса, содержащего менее конкретный тип возврата:
abstract class Animal {Это значительное улучшение, поскольку теперь вы можете избежать приведения возвращаемого значения во время выполнения при использовании дочернего типа:
public abstract Food GetFood();
}
class Tiger : Animal {
public override Meat GetFood() => …;
}
var t = new Tiger();Int Нативного Размера
// Раньше
Meat m = (Meat)t.GetFood();
// Сейчас
Meat m2 = t.GetFood();
Это новая конструкция, которая позволяет объявлять
int
, размер которого определяется платформой: 32 или 64 бита. nint
и nuint
- новые ключевые слова для этого.Такая возможность уже существовала с
IntPtr
и UIntPtr
. nint
и nuint
- это просто оболочки над этими типами, предоставляющие дополнительные возможности, такие как преобразование и арифметические операции, которые невозможны с IntPtr
. Это может значительно оптимизировать производительность приложения при выполнении интенсивных вычислений, требующих низкоуровневого доступа и где важен каждый байт.Источник: https://blog.miguelbernard.com/c-9-the-unknown-goodies/