Quic от Google

Основной обязанностью любого транспортного протокола является поддержка связи и коммуникации между двумя конечными сущностями. Таким сущностями могут выступать хосты и устройства, как, к примеру, роутеры. Транспортный протокол предоставляет механизм виртуального зацикленного пути между двумя конечными устройствам. Есть два типа транспортных протоколов: ориентирующиеся на соединения и не ориентирующиеся. Из названий становится понятно, что в первом типе происходит некоторое количество дополнительной работы на то, чтобы создать соединение и только после этого появляется возможность передачи информации. В свою очередь протоколы, работающие без заранее созданного соединения, нацелены на то, чтобы доставлять информацию, не волнуясь о том была ли она принята или нет, но в таком случае работа по приёму ложится на самих отправителей и адресатов, которые связаны протоколом. В пример можно привести два самых распространённых протокола – это TCP и UDP, соответственно, первый ориентирован на связь, а второй – нет.

Протокол QUIC – новый транспортный протокол, предназначенный для обеспечения соединения с низкой задержкой через Интернет. Новая технология построена на основе протокола UDP (что напрямую отражено в названии — Quick UDP Internet Connections), поэтому с её помощью можно передавать данных без необходимости в выделенном сквозном соединении.

QUIC был разработан компанией Google для решения проблем основного транспортного протокола TCP (Transmission Control Protocol), который широко используется в интернете, однако имеет недостатки среди которых – высокий уровень задержек и проблемы с контролем перегрузок, который могут привести к проблемам с производительностью.

Для решения этих проблем QUIC предоставляет ряд ключевых функций, которые повышают производительность и безопасность, среди них – мультипоточность, приоритезация, управление перегрузками и сквозное шифрование.

Основная часть

Предпосылки появления нового протокола

В самом распространённом на сегодняшний день протоколе TCP сокрыты некоторые недостатки, приносящие проблемы во время работы интернет-инфраструктуры, от которых хотелось бы избавиться.

Например, полуоткрытые соединения. Проблему здесь проще понять на примере: представьте, что было объявлено соединение между сервером и клиентом, если сервер во время первичного рукопожатия не смог получить от клиента ACK, то порт, выделенный для этого соединения, продолжает существовать и находится в полуоткрытом состоянии, ожидая необходимой информации для полноценной его работы. И находится в таком состоянии он будет до тех пор, пока не выйдет время, заложенное на подключение, после этого порт будет закрыт.

Также довольно часто возникает проблема блокировки началом очереди. Простыми словами её можно определить так: когда потеря одного объекта мешает передаваться следующим. Тут проблема возникает из-за самой работы TCP, она построена по принципу FIVO – first in first out, то есть данные передаются последовательно и не пакет из конца очереди не может попасть в начало. В TCP эта проблема решается так: пакет, находящийся после потерянного, сохраняется в буфер и хранится там до тех пор, пока ему не придёт копия потерянного пакета.

История QUIC

QUIC был разработан компанией Google в качестве экспериментального протокола для внедрения в HTTP, но позже был признан главным протоколом транспортного уровня модели OSI. Впервые его показали общественности в 2013 году. Новый протокол был разработан с целью оптимизации и повышения производительности путём решения проблем высокой задержки и контроля перегрузок, которые могут повлиять на работу TCP.

За годы с момента появления QUIC был широко внедрён компанией Google. Создатели протокола активно переводили свои сервисы на новую технологию и уже к сегодняшнему дню мы видим, что все подконтрольные им сервисы используют новый протокол как основной. Помимо этого, Google также заявили, что на сегодняшний день уже более половины запросов их браузер Chrome обрабатывает по новым стандартам. QUIC также получил распространение за пределами Google и поддерживается рядом других компаний и организаций, включая Mozilla, Cloudflare и Инженерный совет Интернета (IETF).

Ключевым для протокола событием стало его принятие в качестве стандарта сообществом IETF, поскольку именно IETF занимается стандартизацией протокола для повсеместного внедрения. И впоследствии Инженерный совет Интернета назначил крайний срок для принятия комментариев на ноябрь 2021 года в теме обсуждения будущего протокола HTTP3, в котором QUIC стал основным транспортным протоколом. После окончания обсуждений третья версия трансферного протокола может быть использована.

Устройство QUIC

QUIC в модели OSI находится на уровне приложений, что очень отличает его от других протоколов, которые находятся на транспортном уровне. Такое нестандартное положение протокола позволяет ему быть высоко-совместимым с конечными сущностями. QUIC очень похож на стек из TCP + TLS + HTTP2, но поскольку он построен на UDP, который не ориентирован на связь, все обязанности в стабильности выполняются на уровне приложений.

Решение проблем TCP в QUIC

 До недавнего времени TCP являлся основным транспортным протоколом в Интернете, который отвечает за обеспечение надёжного соединения между устройствами, однако TCP имеет ряд недостатков, которые так или иначе решены в QUIC

  • Миграция соединения

    В QUIC соединения идентифицируются с помощью 64-битного ID, который можно продолжать использовать даже после смены IP адреса пользователем. Из-за этого при смене IP адреса пользователя не возникает разрыва соединения, которое случается при смене на TCP. Также важно отметить, что на практике это довольно часто возникающая ситуация, особенно для смартфонов.

  • Оптимизированный ACK

    В QUIC каждый пакет имеет свой уникальный последовательный номер, поэтому не возникает проблемы различия пакетов при их ретрансмите. В QUIC поддерживается до 256 диапазонов NACK, помогая отправителю быть более устойчивым к перестановке пакетов и использовать меньше байтов в процессе. В TCP используется выборочный SACK, который решает проблему не во всех случаях.     

  • Восполнение потерь

    В QUIC вызывается два TLP до того, как сработает Retransmission TimeOut (RTO), что отличается от реализации в TCP. Это позволяет быстрее обрабатывать восполнение хвостовых задержек, особенно для коротких и чувствительных к задержкам передач.     

  • Управление перегрузкой

    QUIC находится в модели OSI на уровне приложений, позволяя проще обновлять главный алгоритм транспорта, который управляет отправкой, основываясь на параметрах сети. Большинство TCP-реализаций используют алгоритм CUBIC, который не оптимален для трафика, чувствительного к задержкам. Недавно разработанные алгоритмы вроде BBR, более точно моделируют сеть и оптимизируют задержки. QUIC позволяет использовать BBR и обновлять этот алгоритм по мере его совершенствования.

  • Многопоточность

    QUIC позволяет передавать несколько потоков данных через одно соединение, снижая расходы на создание и поддержание отдельных связей для каждого потока. В свою очередь TCP ничего подобного не имеет, поэтому для передачи данных несколькими потоками при работе с ним приходится открывать несколько различных соединений.

  • Приоритезация потоков

    QUIC позволяет устанавливать приоритеты потоков в зависимости от важности передаваемых данных, что позволяет ускорять процесс.

  • Шифрование

    QUIC по умолчанию обеспечивает сквозное шифрование, помогая защитить передачу данных. Для шифрования в QUIC используется TLS 1.3, который устанавливает ключи сессии, а после этого шифрует каждый пакет информации. В TCP также используется TLS, но из-за этого появляется необходимость в дополнительном рукопожатии между клиентом и сервером. В QUIC же этого не происходит, поскольку он соединяет собственное рукопожатие с RTT от TLS. Также в QUIC заменён записывающий слой TLS на собственный формат, но при этом сохраняется полная совместимость, и при этом ещё передаются дополнительный метаданные с целью защиты от манипуляций соединением через firewall и proxy.

Дополнительно в QUIC

  • QPACK

    В HTTP второй версии были представлены сжатые заголовки — HPACK, которые позволяет конечным хостам сокращать количество передаваемой информации. В частности, HPACK имеют динамические таблицы, заполненные предыдущими HTTP запросами и ответами. Это позволяет хостами обращаться к прошлой информации без необходимости запрашивать её снова. Используя TCP, HTTP запросы и ответы отправляются по порядку их пришествия, последовательно. А QUIC при помощи мультипоточности может отправлять их во множественном количестве одновременно, но тогда не гарантируется последовательность отправки пакетов.

  • QUIC заголовки

    Заголовки в QUIC бывают двух типов: длинные и короткие. Различают их по объёму передаваемой информации, в длинных её хранится больше. Длинные заголовки хранят в себе информацию о версии, ID адресата и отправителя и различные флаги, как например, форма заголовка. В самом частом сценарии длинные заголовки используются для первичного рукопожатия, но как только соединение установлено, отправитель начинает отправлять короткие пакеты, которые являются наиболее часто используемой опцией в трафике QUIC. В коротких пакетах хранится информации об ID адресата, номере самого пакета и зашифрованная информация пакета.

  • ID связи

    В QUIC существует Connection ID или CID. У каждой связи есть свой набор CID, каждый из которых может быть использован для выделения связи. CID независимо выбирается конечными приложениями, между которыми происходит отправка. Целью CID является доставка информации до получателя независимо от смены его UDP или IP адреса в сети

  • Stream Frame

    Поскольку QUIC подключается клиент и сервер одним соединением, появляется необходимость создания нескольких потоков внутри этого соединения для передачи данных в режиме мультиплекс. Этим и занимается Stream Frame, он создает несколько внутренних потоков, доставляющих информацию. В каждом таком потоке есть механизм контроля данных и отслеживание потерь, если потеря происходит, то это не влияет на другие потоки. В каждом потоке содержится информация о его порядковом номере, смещение, которое позволяет определить откуда потоку начинать передавать пакет, длину передаваемой информации и само содержимое.

  • Нумерация пакетов

    Нумерация представлена числом в диапазоне от 0 до 2^.61 - 1. Это используется для определение криптографического одноразового номера защиты. Каждая конечная точка поддерживает отдельный номер пакета для отправки и получения. Номера пакетов ограничены, потому что им необходимо быть представленными целиком в поле ACK. Номера пакетов могут быть сокращены и кодироваться в от 1 до 4 байт.

Сравнение TCP и QIUC

QUIC основан на UDP и был разработан для решения проблем TCP, который является доминирующим транспортным протоколом, используемым в Интернете.

Одним из ключевых различий между QUIC и TCP является способ, которым они обрабатывают передачу данных. TCP — это протокол, ориентированный на связь, который устанавливает выделенное сквозное соединение между устройствами для передачи данных. Оно поддерживается в течение всего времени передачи, и данные передаются надежным, упорядоченным образом. QUIC, с другой стороны, является протоколом без связи, который позволяет передавать данные без необходимости в выделенном сквозном соединении. Это обеспечивает большую гибкость и может привести к снижению задержки, поскольку уменьшаются накладные расходы на установление и поддержание соединения.

Чтобы сравнить скорость работы протоколов хорошо подойдёт следующая иллюстрация:

На ней мы видим большой прирост скорости QUIC даже в сравнении с TCP без шифрования. Поскольку QUIC основан на UDP, для передачи информации нет необходимости в том, чтобы отправлять RTT в таком же количестве, как это делает TCP. Если связь между клиентом и сервером уже была установлена, QUIC не будет отправлять никаких RTT, но, если связь первичная, один RTT всё же будет отправлен. Это положительно сказывается на скорости передачи данных.

Проблемы нового протокола

Несмотря на то, что QUIC оказался вполне успешным и был широко принят компаниями и организациями, при его использовании могут возникать сложности и проблемы.

Одной из таких можно назвать его сложность. Из-за того, что QUIC включает в себя ряд расширенных функций, он может оказаться более сложным в отладке и реализации, чем его аналоги, что может стать проблемой для разработчиков и затруднить устранение возникающих проблем.

Также стоит упомянуть о проблеме оценки качества сети с новым транспортным протоколом. В такой сети невозможна оценка RTT и потерь пакетов путём простого наблюдения за соединением, там недостаточно информации для этого. Отсутствие наблюдаемости вызвало серьёзную озабоченность у некоторых представителей сообщества операторов связи. Они говорят, что такие пассивные измерения критически важны для отладки и анализа их сетей.

Не обошлось и без проблем с памятью. Поскольку QUIC находится на уровне приложений в модели OSI, он использует больше оперативной памяти, чем обычно это делает TCP. Также в QUIC существует ограничение на максимальный размер передачи (Maximum Transmission Unit) в 1392 байта, что пока не позволяет ему задействовать фрагментацию.

Выводы

QUIC точно привнесёт что-то новое в IoT отрасль. Поскольку траффик там немного отличается от обычного пользовательского интернет-трафика и работают устройства умного дома в сетях с высокими потерями, использование TCP в качестве основного протокола – ошибка. В свою же очередь QUIC может легко работать внутри таких сетей и эффективно справляться со своими задачами благодаря Connection ID.

QUIC решает многие проблемы TCP, что позволяет ему работать лучше и в условиях обычного интернета и HTTP трафика, поскольку поддерживает многоуровневость и устраняет неэффективность в его стеке.

С момента своего появления QUIC получил широкое распространение и использование, и в настоящее время поддерживается рядом компаний и организаций, помимо Google, хотя и является довольно новой технологией. Он стал нововведением для повышения производительности и безопасности приложений в Интернете, и его принятие и развитие сыграли значительную роль в улучшении глобальной сети. Поскольку Интернет и потребности приложений продолжают развиваться, вполне вероятно, что в QUIC будут добавлены новые составляющие для улучшения его производительности.

Список используемой литературы

  1. Google. (2021). QUIC: Overview. Источник: https://peering.google.com/#/learn-more/quic

  2. Habr. (2015). Google успешно использует новый интернет-протокол QUIC в работе браузера Chrome. Источник: https://habr.com/ru/post/378543/

  3. Habr (2016). Протокол QUIC: переход Web от TCP к UDP. Источник: https://habr.com/ru/company/infopulse/blog/315172/

  4. Habr. (2021). Транспортный протокол QUIC приняли в качестве стандарта RFC 9000 Источник: https://habr.com/ru/company/globalsign/blog/560342/

  5. Habr. (2018). Протокол HTTP-over-QUIC официально становится HTTP/3. Источник: https://habr.com/ru/company/globalsign/blog/429820/

  6. Habr. (2019). TCP против UDP или будущее сетевых протоколов. https://habr.com/ru/company/oleg-bunin/blog/461829/

  7. Habr. (2020). Head-of-Line Blocking в QUIC и HTTP/3: Подробности. https://habr.com/ru/company/selectel/blog/532868/

  8. TProger. (2020). Протоколы передачи данных: что это, какие бывают и в чём отличия? https://tproger.ru/explain/protokoly-peredachi-dannyh-chto-jeto-kakie-byvajut-i-v-chjom-razlichija/

  9. QUIC – A Quick Study. (2020). https://arxiv.org/pdf/2010.03059.pdf

Это мой первый пост, рад любой критике.


ссылка на оригинал статьи https://habr.com/ru/post/719598/

Принцип определения дальности между радио трансиверами

Настал второй за 10лет случай, когда в профессии программист-микроконтроллеров понадобилась математика. Она нужна чтобы решить задачу из радиотехники.

Могут ли радио трансиверы определять дальность между собой? Можно сказать: «Да, конечно. Можно отправлять пакеты со своими GNSS координатами». Но что если нет GNSS приемников в составе оборудования? Пусть это вообще indoor оборудование. В чём сложность технологии радио определения дальности? Всё, что есть в распоряжении это возможность пулять и ловить пакеты.

Допустим, что у нас есть возможность точно запоминать моменты времени отправки и приема радио пакетов. После этого сразу жизнь становится намного веселее.

Тогда формально можно вычислить интервалы t_fly, t_delay, t_loop. Итак, дано:

Переменная

Комментарий

Единица измерения

t_tx

Время отправки на трансивере A

с

t_rx

Время приема на трансивере А

с

T_tx

Время отправки на трансивере B

с

T_rx

Время приема на трансивере B

с

с

Скорость света в воздухе

м/c

Найти расстояние R между трансиверами и выразить его в метрах.

Tак как радиоволны распространяются со скоростью света, то получается, что зная t_fly можно вычислить расстояние между трансиверами. R=c*t_fly.

Называется эта технология Time Of Flight (ToF). Всё на бумаге кажется ровным. Даже нет нужды в синхронизации начала счета часов двух трансиверов. Кажется что всё прекрасно. Однако нет. Тут же возникают неприятные вопросы: Какая нужна точность измерения времени отправки? Как добиться одинакового периода увеличения разрядов в двух таймерах? Каков механизм регистрирования TimeStamp(ов)?

Какое должно быть разрешение таймера измерения времени?

Допустим мы хотим измерять расстояние с точностью +-5см. Сколько времени нужно свету чтобы пройти 5см?

свету надо 166ps чтобы пролететь 5см
свету надо 166ps чтобы пролететь 5см

Свету надо 166ps, чтобы пролететь 5см. Это значит, что аппаратный таймер должен тактироваться на частоте более 5995849160 Hz =5995849.16 kHz=5995.84916 MHz=5.99584916 GHz.

Нужен всего-то таймер на 6+GHz. И можно начинать говорить про radio ranging. Есть ли такие аппаратные таймеры в ASIC радио чипах? Ответ: да.

Как добиться одинакового периода увеличения разрядов в двух таймерах?

Можно поменять местами initiator и responder и повторить процесс, а затем взять среднее арифметическое от двух рассчитанных расстояний.

Акроним

Расшифровка

ps

picoseconds

ASIC

application-specific integrated circuit

PLL

phase lock loop

с

скорость света 299,792,458 м/c

ToF

time of flight

GNSS

Global navigation satellite system

Вывод

Если присутствует механизм точного измерения моментов времени приема и отправки радио пакетов, то можно определять дальность между трансиверами. При этом синхронизация часов не требуется. Однако важна высокая скорость счета часов (+1 за 166ps), высокое разрешение такого таймера и высокая воспроизводимость технологии изготовления стабильных кварцевых резонаторов с PLL. При выполнении этих условий можно делать измерение расстояния между радио трансиверами.

Links

https://habr.com/ru/company/realtrac/blog/282698/
https://habr.com/ru/post/478140/
http://latex.codecogs.com/eqneditor/editor.php

https://www.youtube.com/watch?v=NrSfeQoOvqg

https://www.youtube.com/watch?v=zA27p0Pj30U

https://www.youtube.com/watch?v=5KN4dJdkHUk

https://www.youtube.com/watch?v=5KN4dJdkHUk&t=126s

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Вы программировали UWB трансиверы?
21.43% да 3
78.57% нет 11
Проголосовали 14 пользователей. Воздержались 2 пользователя.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Вам удавалось реализовать/воспроизвести технологию Time Of Flight?
22.22% да 2
77.78% нет 7
Проголосовали 9 пользователей. Воздержались 5 пользователей.

ссылка на оригинал статьи https://habr.com/ru/post/719542/

Листиклс – простой метод сравнительного анализа вашего предложения с альтернативами

Жил-был продакт-менеджер

У меня есть убойная идея для нового продукта! Он будет круче всех.  У него будет вот такая классная функция, и вот такой крутой  интерфейс, с блокчейном и искусственным интеллектом, с блэкджеком и… ну вы знаете…

Сразу будем делать? Или сначала проверим, а кто-то вообще его купит?

Зачем нам тестировать спрос?

В книжках пишут, что гипотезы о спросе нужно проверять еще до разработки, так что сделаем все по-правильному.

Необходимо убедиться в том, что:

  1. На рынке есть реальная проблема, которую может решить мой крутой продукт

  2. Рынок в курсе этой проблемы и настроен решить ее

  3. Мой продукт способен решить эту проблему

  4. Мой продукт решает проблему значительно лучше, чем его альтернативы, с точки зрения рынка.

  5. Я могу транслировать ценность моего продукта таким образом, чтобы убедить рынок выбрать его, а не прочие альтернативы.

  6. Предполагаемая цена будет конкурентоспособной и привлекательной.

Да, работы много, ну да ладно.

Методы исследования  спроса

Есть качественный и количественный методы исследования спроса. Для хорошего результата  нужны оба.

C качественным методом все просто: нужно будет  провести интервью с достаточным количеством людей из целевой аудитории, чтобы вникнуть в их проблемы, задачи  и потребности. Это также поможет узнать, какими альтернативами моему продукту рынок пользуется сейчас. 

Качественный метод, с другой стороны, не так прост. Всегда можно создать лендинг, но тут есть  проблемы:

1. Привлечь трафик на лендинг достаточно сложно и дорого, особенно на конкурентном рынке.

2. Это в большей степени тестирование рекламы, нежели моего продукта, и правильно подобрать ее будет достаточно сложно, особенно учитывая небольшой бюджет. Это отвлекает от работы над ценностным предложением самого продукта

3. И самое главное – нельзя будет оценить, насколько мой продукт более или менее привлекателен, чем существующие альтернативы, а это — главное. Какую бы я не получил конверсию на лендинге — ее не с чем сравнить, так как данных о конверсии конкурентов и альтернатив нет.

Но есть и другой подход.

Статьи-списки (от английского слова listicles = list + articles)

Вы наверняка видели статьи из серии «Лучшие N того-то и того-то»? Например,

•5 лучших автомобильных GPS-трекеров

•14 продуктов для роста волос, которые действительно работают

•Топ 10 лучших CRM в 2023 году

Их часто называют «статьями-списками», т.е. статьями, представленными в виде списков.

Они позволяют читателям избежать значительной траты времени на собственное исследование возможных решений проблемы, а вместо этого-  воспользоваться результатами чужого исследования, сразу получить список  лучших решений и выбрать среди них.

Кроме того, они предлагают объективное и беспристрастное сравнение лучших вариантов вместо рекламной презентации, созданной с  преувеличением преимуществ и преуменьшением недостатков. По крайней мере, такое впечатление они создают.

Я постоянно такими пользуюсь: они значительно упрощают выбор нового телефона, приложения или кино для вечернего просмотра. Более того, я использую их и на работе, когда ищу способы решения повседневных задач.

Что, если мы воспользуемся этим форматом для сравнения нашего продукта с наилучшими доступными альтернативами?

План действий

Итак, вот мой план:

  1. Я проведу исследование и составлю список лучших  альтернатив для решения проблемы, которую должен решить мой продукт. Речь не только о конкурентных продуктах. Например, альтернативой CRM может быть и доска со стикерами в офисе продаж.

  2. Я напишу статью «Топ 5 решений {проблемы X}», куда включу и свой продукт.

  3. Я постараюсь написать статью так, чтобы она была  объективным и беспристрастным анализом. Я не буду преувеличивать преимущества моего продукта и не буду преуменьшать его недостатки. И  буду столь же честен в отношении альтернатив.

  4. Я сравню все решения относительно преимуществ, которые, на мой взгляд, наиболее важны для моей аудитории: цены, удобства использования, набор фич,  документация и т.п.

  5. Я размещу статью на нейтральном домене (не на сайте моего продукта). При этом важно, чтобы у меня был доступ к аналитике.

  6. Я буду продвигать статью с помощью рекламы, что должно быть проще и дешевле, чем продвижение конкретного решения: людям обычно не нравится, когда им что-либо продают.

  7. Я буду отслеживать поведение посетителей: что они делают, когда оказались на странице, по каким ссылкам переходят, какой текст выделяют. Можно даже сделать запись экрана пользователей (используя, например, HotJar), чтобы понять их поведение на странице.

  8. Также я оценю, насколько легко привлечь трафик на эту страницу. Если люди не переходят на нее, это может означать, что та проблема, которую я хочу решить, не так уж и важна для моего целевого рынка.

  9. Я оценю, насколько популярно мое решение в сравнении с альтернативами.

  10. Я буду пробовать  разные формулировки описания своего решения и его основных преимуществ с помощью А/Б тестирования, пока не буду удовлетворен тем, как часто пользователи выбирают мое решение.

Дисциплинируем мышление

Я вижу преимущества уже на этапе написания такой статьи в виде дисциплинирования своего мышления.

  1. Это заставляет меня четко понять проблему, которую я решаю.

  2. Необходимо будет изучить наилучшие из имеющихся решений.

  3. Придется заранее задуматься о дифференциации моего продукта.

Возможные результаты

После публикации статьи и привлечения трафика возможны следующие результаты:

  1. Есть вероятность, что я не смогу привлечь значительный трафик на страницу. Так как мой рынок устоявшийся и не супернишевый, это скорее всего значит, что рынку эта проблема не актуальна.

  2. Очевидно, что посетители могут предпочесть альтернативы, а не мое решение. В общем-то я этого и ожидаю при первой итерации. Однако, это не плохо — с этого момента я могу проводить A / B тестирование различных версий ценностного предложения моего продукта, чтобы добиться хороших показателей.

  3. Я могу дойти до момента, когда  у меня будет неплохое количество посетителей и хороший коэффициент конверсии моего крутого продукта по сравнению с альтернативами. Это будет достаточно весомым подтверждением спроса на продукт, и можно будет смело браться за разработку.

Резюме

Я уверен, что у статей-списков есть огромный потенциал для проверки гипотез о спросе.

  1.  Пока вы пишете статью, вы дисциплинируете мышление, задумываясь  над проблемой, альтернативными решениями и дифференциацией  на раннем этапе.

  2. Их легче продвигать, что делает весь процесс проще и доступнее.

  3. Они валидирует проблему, демонстрируя на раннем этапе интерес рынка к решениям. 

  4. Они позволяют вам сравнить ваше ценностное предложение с наилучшими доступными альтернативами.

Пробовали ли вы использовать метод статьи-списка для оценки спроса? Если да, напишите  в комментариях, как это сработало.


ссылка на оригинал статьи https://habr.com/ru/post/719604/

Лабиринт внутри лабораторной мышки

Что беспокоит Google. И как можно исправить ситуацию.

There must be some way out of here, said the joker to the thief

There’s too much confusion, I can’t get no relief

— All Along the Watchtower Боба Дилана, настоящего «барда» современности

Я пришел в Google незадолго до пандемии, когда компания AppSheet, в которой я был одним из основателей, была поглощена Google Cloud. Команда поглощения и руководство компании радушно приняли нас и прекрасно к нам относились. Мы влились в коллектив с большим энтузиазмом и готовностью интегрировать AppSheet в Google и сделать проект успешным. Однако теперь, по истечении трех лет обязательного контракта, я уволился из Google, осознав, что некогда великая компания потихоньку перестает работать как должно.

В Google работает 175 000+ умелых и хорошо оплачиваемых сотрудников, однако из квартала в квартал, из года в год они практически ничего не делают. Как лабораторные мыши, они заперты в лабиринте согласований, процедур внедрения, юридических проверок, аттестаций, совещаний, документов, отчетов об ошибках, сортировок, OKR, планов H1, за которыми следуют планы H2, общих собраний и непрекращающихся реорганизаций. Мышам регулярно подбрасывают «сыр» (повышения, бонусы, шикарная еда, фантастические привилегии), и, несмотря на то, что многие хотят ощутить личное удовлетворение и отдачу от своей работы, система заставляет их подавить эти неуместные желания и научиться тому, что на самом деле значит быть «гуглообразным» (Googley) — нужно сидеть смирно и не раскачивать лодку. Как выразился в своем бизнес-памфлете Дипак Малхотра, проблема более не заключается в том, что мышка попала в лабиринт. Проблема в том, что «лабиринт оказался внутри самой мыши».

Google, особенно с учетом давления OpenAI + Microsoft, оказалась в очень шатком положении. Многие воспринимали эту проблему сугубо с технологической точки зрения, однако даже у них понемногу закрадывается мысль, что это симптом какого-то более серьезного кризиса. Недавние сокращения вызвали недовольство сотрудников, поскольку многие из них расценили случившееся как просчет руководства или уступку инвесторам-активистам. В какой-то степени это свидетельствует об общем недостатке осознанности как у руководства, так и у сотрудников. Фундаментальные проблемы Google лежат в культурной плоскости, а все остальное — лишь ее отражение. Безусловно, я не единственный, кто наблюдает эти проблемы (см. пост Ноама Бардина, основателя Waze и бывшего сотрудника Google).

На мой взгляд, у Google есть четыре главные культурные проблемы. Все они — естественные следствия обладания деньгопечатным станком под названием «Ads», ведь он продолжал неутомимо разгоняться из года в год, пряча все остальные грешки под ковер.

(1) Отсутствие миссии, (2) отсутствие обязательности, (3) иллюзия исключительности, (4) бесхозяйственность.

К сожалению, я не впервые наблюдаю процесс распада господствующей империи. Более десяти лет (1999-2011) я проработал в другой великой компании (Microsoft), в то время как она планомерно деградировала и сбивалась с пути. Тем не менее, у Google есть несколько сильных сторон, которых не было у Microsoft, когда она пыталась оправиться: в компании не прижились эгоцентризм и феодальные замашки, люди ценят самоанализ, заявленные ценности компании незыблемы, а весь остальной мир по-прежнему уважает Google. У Google и у моих друзей, которые там сейчас работают, есть надежда, но для ее реализации потребуются активные действия.

Businessmen they drink my wine, plowmen dig my earth

None of them along the line, know what any of it is worth

Неужто хоть кто-то в Google приходит на работу, реально размышляя об «организации мировой информации»? Люди утратили представление о том, кому и зачем они служат. Ежедневно вкалывая в стартапе в течение восьми лет, я знал ответ на этот вопрос: «Я служу нашим пользователям». Увы, лишь некоторые сотрудники Google выходят на работу с осознанием того, что они работают на благо клиента или пользователя. Как правило, они посвящают себя какому-то обезличенному процессу («Я отвечаю за систему конфиденциальности») или какой-то технологии («Я поддерживаю работу системы CI/CD»). Они служат своему менеджеру или вице-президенту. Они обслуживают других сотрудников. Они могут даже прислуживать каким-то общим техническим или религиозным убеждениям Google («Я эксперт по читаемости кода»). Это закрытый мир, где почти все работают друг на друга, а цикл обратной связи основан на том, что твои коллеги и менеджеры думают о твоей работе. Усердная или интеллектуальная работа не создают в таком мире никаких фундаментальных ценностей. Более того, странным образом всё получается наоборот.

Несмотря на то, что двумя главными ценностями Google являются «уважение к пользователю» и «уважение к возможностям», на практике системы и процессы намеренно разработаны так, чтобы «учитывать риски». Снижение рисков ставится выше всего остального. Это имеет смысл, если все идет замечательно и самое главное — не раскачивать лодку и продолжать плыть по течению на растущем приливе доходов от рекламы. В таком мире потенциальный риск лежит везде, куда ни глянь. Люди поступают соответствующим образом:

  • Каждая строчка кода, которую ты меняешь, — это риск, поэтому внедряй тонну процессов, чтобы гарантировать, что каждое изменение кода будет максимально безопасным (и неважно, если пользователю это выйдет боком).

  • Все, что ты внедряешь, — это риск, поэтому необходимо провести тонну проверок и согласований (в буквальном смысле, для внедрения нового инструмента нужно 15+ согласований, что сравнимо со сложностью запуска космического корабля в NASA) лишь чтобы добавить третьесортную функциональность в какой угодно, даже самый завалящий продукт.

  • Любое нестандартное решение — это риск, поэтому избегай всего, что не соответствует коллективной практике и общепринятым устоям.

  • Любое изменение привычного порядка вещей — это риск, поэтому делай как раньше и не выпендривайся.

  • Каждый неудовлетворенный сотрудник — это риск для твоей карьеры, поэтому менеджеры стремятся к 100%-ной удовлетворенности работников и деликатно обращаются даже с самыми слабыми сотрудниками (при этом недовольные клиенты риском не считаются, если только это не «крупняки», поэтому удовлетворенность клиента — это всего лишь метрика, о которой вспоминают только на групповых митингах).

  • Любое несогласие с управленческой цепочкой — это риск для карьеры, поэтому всегда говори «да» вице-президенту, держа в уме, что вице-президент говорит «да» старшему вице-президенту, и так до самого верха.

Положение дел изменилось бы, если бы фокус сместился на создание ценностей. Если ежедневно ты будешь спрашивать себя: «Что хорошего и для кого я сегодня сделал?», ты придешь к совершенно иным результатам. Если каждый полугодовой план будет определять «минимальное количество пользы, принесенной миру», это приведет компанию и ее работников к совершенно новому образу мысли. Я сам работал бы с большей отдачей, если бы мой труд приносил больше пользы и оказывал влияние на остальных. Но я вынужден себя ограничивать, чтобы не давать людям совершать ошибки — оказывается, гораздо проще и эффективнее работать медленно и тормозить своих коллег. Достаточно попросить еще несколько уточнений и запланировать еще один раунд встреч через две недели. Не зря я не стал чиновником, инспектором ЖКХ или правительственным бюрократом. Это прекрасные профессии, но в Google им не место, если компания на самом деле хочет изменить мир.

No reason to get excited, the thief he kindly spoke

There are many here among us who feel that life is but a joke

Одна из главных ценностей Google — «уважение друг к другу». Ее можно трактовать по-разному: я вот надеялся, что речь идет об уважении уникальных сильных сторон каждого человека и о том, как добиться того, чтобы каждый человек максимально раскрыл свой потенциал и влияние. К сожалению, всё это разбивается о всеобъемлющую организационную инертность и нежелание что-либо менять. «Уважать друг друга» переводится с гугловского как «найти способ учесть мнение каждого человека и смириться с ним». В инклюзивной культуре (в ней хорошо, что информация о проекте и возможности доступны каждому участнику) с крайне распределенной ответственностью (а вот это уже плохо) ты быстро приходишь к тому, что для принятия любого решения нужно получить одобрение сразу от кучи людей. Если бы это был алгоритм, мы назвали бы его «побеждает самый осторожный», и практически всегда находится человек, предпочитающий вообще ничего не делать, лишь бы ничего не сломать. Плюс зачастую люди, вовлеченные в процесс, обладают совершенно разными знаниями, возможностями и ролями, поэтому всегда будет находиться человек, которому настолько некомфортно, что он сложит лапки и зарубит процесс на корню. Поэтому любое решение, выходящее за рамки заранее утвержденного плана или отклоняющееся от общепринятых представлений, практически невозможно воплотить в жизнь, равно как и утвержденный план практически не подлежит изменению.

Итак, в рамках заранее утвержденного плана (например, команда Х работает над продуктом Х) приоритетом является стремление к предсказуемости с минимальными рисками. Каждый менеджер пыжится выглядеть уникально мудрым, предлагая свою интерпретацию модели «недообещать и перевыполнить», хотя по факту это чистая глупость, а не проявление ума. Я еще не видел ни одной инженерной команды, которая перевыполнила бы свои обязательства. Эта ошибка коренится в культуре управления, основанной на занижении ожиданий. Существуют документы, которые явно и не без гордости высмеивают «героизм» и утверждают, что продуктовые команды не только не должны поощрять «героев», они должны активно их отговаривать. Если кто-то решит работать в два раза усерднее, чем ожидается, ему наверняка помешают, так как придется и всех остальных делать вдвое продуктивнее. Если кто-то заикнется, что сможет закончить проект за месяц, менеджер попросит его быть реалистом, увеличит срок до четырех месяцев, а вице-президенту доложит, что речь идёт о полугодии. Они могут говорить и даже верить, что лучше не торопиться, зато делать всё правильно, но это вовсе не значит, что ошибок не будет; это значит лишь, что работа займет кучу времени.

Общая картина такова: это мягкотелая культура мирного времени, в которой нет ничего, за что стоило бы бороться. Люди, склонные биться за клиентов, новые идеи или креативность, очень скоро познают обратную сторону медали. У компании по определению нет стимула идти выше и дальше, поэтому коллеги и менеджеры будут смотреть на тебя косо, если ты попытаешься выделиться. Предполагается, что ты должен выполнять работу в соответствии со своим положением на карьерной лестнице. От инженера-программиста уровня L5 ждут определенных действий, и его работа будет оцениваться в соответствии с этой шкалой. Слово «клиент» не входит в эту схему, поэтому не стоит утруждать себя поддержкой клиентов и ждать, что тебя за это похвалят. Не пытайся быть новатором или делать что-то, чего нет в официальном плане, составленном шесть месяцев назад, потому что даже если ты это сделаешь, руководители всё равно не изыщут для тебя ресурсы, связанные с разработкой, PM, Pgm, UX, документацией, юридическими и маркетинговыми вопросами, без которых проект не запустить. Тем не менее, твой код должен быть хорошо отформатирован (когорта разработчиков не приемлет иного!), к тому же тебе нужно убедиться, что в коде равномерно расставлены проверки (вообще без разницы, зачем и почему). После этого подожди пару лет, тебя повысят, и ты сможешь перейти в другую команду внутри Google. Всё так, как говорил Ноам Бардин из Waze — несмотря на то, что каждый человек руководствуется благими намерениями, у системы есть собственная динамика. И в этой системе нет ничего, за что бы стоило бороться.

But you and I have been through that, and this is not our fate

So let us not talk falsely now, the hour’s getting late

Внутри Google существует коллективное заблуждение, что их компания исключительна. И как это бывает во всех подобных случаях, обманутые — простые смертные, стоящие на плечах действительно исключительных людей, которые прошли до них и создали условия для невероятного успеха. В конце концов, исключительные преимущества начинают угасать, но затянувшееся заблуждение искоренило смирение среди простых смертных, оставшихся в компании. Ты не просыпаешься каждый день с мыслью о том, что ты должен делать лучше, что твои клиенты заслуживают большего и что ты мог бы работать эффективнее. Вместо этого ты веришь, будто то, что ты делаешь уже сейчас, настолько идеально, что стремиться дальше не к чему. Пропаганда приобретает важное внутреннее и внешнее значение. Когда новые люди приходят в твою компанию, ты вводишь их в заблуждение. Ты настаиваешь на том, что и как надо делать, потому что «именно так мы делаем это в Google». Плевать, если большинство людей жалуются на общую неэффективность и некомпетентность. Вот несколько примеров:

  • У Google есть уникальный внутренний технологический стек под названием «Google3». Все масштабные потребительские продукты компании построены на этом стеке. Существует заблуждение, что Google обладает лучшим технологическим стеком в мире. Возможно, это и было правдой десять лет назад, но сегодня это точно не так. Много других компаний построили масштабные потребительские сервисы без этого специфического стека. Так что же это означает? Может быть, не стоит запрещать все остальные полезные технологии, которыми во всем мире люди пользуются для ускорения своей работы. Например, React! Или SaaS-сервисы, такие как Twilio, Intercom и Mixpanel! Может быть, они помогут компании эффективнее нанимать сотрудников и быстрее внедрять инновации. Чтобы идти в ногу с миром, следует ослабить хватку и перестать бояться нового.

  • Внутренние процессы в Google, бесспорно, устарели. Такое ощущение, что компания двадцать лет назад застряла во временной аномалии, где нет ничего лучше, чем Waterfall. Если все старшие менеджеры в команде тратят по одному месяцу из каждых шести на планирование, один месяц уходит на отпуск и один месяц на проведение аттестации, то внезапно появляется достаточно времени для проведения реорганизации и изменения стратегии раз в год, верно? Ничего не делается, никаких проблем, никакого риска — раздавай премии и бонусы и продолжай в том же духе.

  • Ценности Google гласят: «Уважай пользователя», но компания весьма далека от того, чтобы уделять особое внимание успеху клиента. Если покупатель не платит огромные деньги, он получает в поддержку какого-нибудь слабо информированного инженера техподдержки, который знает о продукте гораздо меньше, чем сам клиент, и ему приходится бегать туда-сюда, чтобы родить еще один бесполезный ответ (но ура, время до первого ответа составило менее 30 минут, так что приборная панель успеха клиента светится зеленым цветом!) Все на всех уровнях будут тратить сотни часов на подготовку единственной презентации для руководителей, но помогать клиенту (лишь бы успеть ответить в течение десяти минут!) будет самый младший сотрудник, а зачастую даже не штатный работник.

All along the watchtower, princes kept the view

While all the women came and went, barefoot servants too

Я проходил собеседование и получал предложения о работе в Google сперва в 2005 году, а потом еще раз в 2009 году. Несмотря на то, что оба раза я отказался, я был очень впечатлен тем, насколько эта компания отличается от прочих. Им хотелось знать, есть ли у меня амбициозные идеи или планы, как изменить мир к лучшему. Тогда им этого по-настоящему хотелось, и именно таких, сильных и вдохновенных людей они искали. Знаете, как дело обстоит теперь?

За считанные годы Google более чем удвоила свой штат, несмотря на продолжающийся отток кадров. Я пришел в компанию в начале 2020 года, а примерно в 2022 оказалось, что я работаю в Google дольше, чем половина всех ее сотрудников. Такой темп найма — это всегда проблема, поскольку он приводит к неудачным кадровым решениям, а неудачные кадровые решения порождают еще более неудачные кадровые решения. «Плохой» — понятие субъективное: каждый человек может быть индивидуально хорош, но поставят ли его на такую должность, где он раскроет свои сильные стороны и нивелирует слабые? Это трудно сделать в спешке. На низших позициях у Google сложный процесс собеседования, и общее качество нанимаемых сотрудников весьма высоко. Большинство этих неискушенных талантов пропадают впустую, и их навыки постепенно атрофируются (но у нас есть превосходный бесплатный массаж, чтобы ты не переживал!). Суть проблемы и ее пагубные следствия кроются в рядах менеджеров и обостряются на уровне директора и выше. Собеседования при приеме на работу на этом уровне полностью субъективны, при этом важную роль играет качество интервьюеров. Google Cloud, в частности, быстро вырос, нанимая специалистов среднего и высшего звена из всех окрестных корпораций. В большинстве случаев навыки, необходимые для того, чтобы стать директором в не самой элитной компании X, не совпадают с навыками, необходимыми для того, чтобы стать эффективным директором в Google. А если людей нанимают из ведущей технологической компании Y, то их либо переманивают на хороший оклад и предлагают новые возможности, либо забирают просто так, для балласта. Иногда происходит первое, но зачастую второе. В отсутствие стабильной и эффективной культуры получается хаотичный суп из сотрудников разномастных фирм, мигрирующих туда-сюда.

Обратная сторона найма — это управление кадрами и их удержание. Судя по тому, что я увидел в Google Cloud, компании следовало бы выявлять и развивать таланты, переводить их на наиболее подходящие роли и в целом оптимизировать работу людей, уже работающих в компании. Однако на практике схема выглядит так: подожди, пока кто-то разозлится и уйдет, а потом возьми на это место первого попавшегося человека. Минимум усилий для того, чтобы направить людей на альтернативные роли и раскрыть потенциал. Это очень расточительно.

Уровень управленческих способностей в разных командах сильно различается, поэтому оценка результатов работы зависит от команды. Тем не менее, гуглеры продолжают верить в миф, возникший в первое десятилетие существования компании, — что все оценки эффективности стандартизированы, и любой человек из любой другой команды Х в Google будет хорошим наёмным сотрудником того же уровня в твоей собственной команде. Это означает, что команды не проводят тщательных внутренних собеседований перед внутренним переводом — только никчемные разговорчики в стиле «пинг-понг».

Существует и ряд проблем с лидерством, отражающихся как в плохих стратегических, так и в тактических решениях. Главным образом потому, что решения принимаются людьми с ролями или титулами, а не с опытом (было бы здорово, если бы эти понятия совпадали!). Почти все важные решения принимаются на уровне вице-президента или выше, обычно людьми, которые обладают положением и любят высказывать свое мнение. Что еще хуже, вице-президенты ротируются между продуктами или приходят из других компаний, но не стесняются принимать критические решения, зачастую почти не зная продукт или его клиентов.

Outside in the distance, a wildcat did growl

Two riders were approaching, the wind began to howl

Google больше не может идти к успеху, избегая рисков. Путь вперед должен начинаться с изменения культуры, и начать придется с самого верха. Высшему руководству Google следует посмотреть на то, что сделал Сатья Наделла в Microsoft, и действовать по аналогичной схеме:

  1. Вести людей, опираясь на четкую миссию. Она должна выходить за рамки технологий (например, использование искусственного интеллекта) или получения денег (например, доходы от облачных вычислений Google). Она должна быть направлена на позитивные изменения для реальных людей (пользователей, клиентов). Гуглеры — идеалисты в душе, и их работа должна что-то значить. Им необходимо верить, что их руководители преследуют какую-то высшую цель, а не просто пересказывают рекламные лозунги.

  2. Отставить «генералов мирного времени», которые недообещают и недовыполняют. Следует наметить амбициозные цели, за которые будет вестись общая борьба.

  3. Избавиться от накопившихся слоев руководителей среднего звена, многие из которых постепенно продвигались по службе сверх своих возможностей и теперь неспособны к изменениям. Нередко они вовсе оторваны от продуктов и команд, которыми управляют.

Может ли Google совершить «мягкую посадку», постепенно трансформироваться и снова стать мощной компанией, продолжая при этом стабильно расти? Большинство компаний не выдерживают этого испытания. Либо они медленно увядают, а затем остаются тенью самих себя (например, IBM), либо терпят эффектный крах (например, AT&T). Microsoft удалось переломить ситуацию, но для этого потребовалось исключительное руководство и удача. У Google есть шанс, и я буду болеть за нее. Мир получит огромные дивиденды, если Google вернётся к своим истокам как амбициозная компания, которая «не делает зла» и стремится сделать мир лучше. Все еще возможно вытащить лабиринт из мышей, а мышей — из лабиринта.


ссылка на оригинал статьи https://habr.com/ru/company/ispsystem/blog/719606/

Гайд по настройке IoC-контейнера в консольном приложении .NET core

Статья-гайд от ведущего .NET-разработчика «ITQ Group» Александра Берегового.

Бывает, что нужно написать консольное приложение без использования IHost, но при этом иметь удобства IoC, поддержку конфигурационных файлов и переменных окружающей среды. В этой статье я как раз и расскажу, как с минимальными усилиями сделать такое приложение.

Итак, для начала, создадим новый проект на базе шаблона Console App.

Укажем имя проекта и путь размещения проекта в файловой системе.

На следующем экране выберем фрэймворк. Я буду использовать .Net 6 LTS.

Я отказался от использования Top-level statements, чтобы не скрывать устройство модуля Program.cs.

После завершения мастера создания проекта, в нашем проекте должен находиться только один модуль — Program.cs, как показано на рисунке ниже.

В модуле Program.cs тоже нет ничего необычного:

namespace ConsoleAppDI {     internal class Program     {         static void Main(string[] args)         {             Console.WriteLine("Hello, World!");         }     } }

Первым делом добавим поддержку конфигурационных файлов. Для этого нам нужно подключить Nuget-пакет Microsoft.Extensions.Configuration.

Теперь мы можем использовать пространство имен Microsoft.Extensions.Configuration. Добавим соответствующую директиву using в модуль Program.cs. После этого добавим в нашу программу новый метод, который будет возвращать ссылку на IConfigurationBuilder — CreateConfigurationBuilder():

using Microsoft.Extensions.Configuration;   namespace ConsoleAppDI {     internal class Program     {         static void Main(string[] args)         {             var configuration = CreateConfigurationBuilder(args).Build();         }           private static IConfigurationBuilder CreateConfigurationBuilder(string[] args)         {             return new ConfigurationBuilder();         }     } }

Теперь добавим в проект конфигурационный файл в формате JSON.

Содержимое конфигурационного файла, сгенерированное Visual Studio, можно удалить, оно нам не понадобится. В свойствах файла appSettings.json нужно включить копирование файла в каталог, в который будет производиться сборка приложения. Для этого в свойствах файла укажите значение Copy if newer, как показано на рисунке ниже.

Теперь зададим путь в файловой системе, где программа должна искать конфигурационный путь. В данном случае будем использовать текущий каталог, в котором исполняется приложение.

using Microsoft.Extensions.Configuration; using System.Reflection; namespace ConsoleAppDI {     internal class Program     {         static void Main(string[] args)         {             var configuration = CreateConfigurationBuilder(args).Build();         }           private static IConfigurationBuilder CreateConfigurationBuilder(string[] args)         {             return new ConfigurationBuilder().SetBasePath(                     Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))                 .AddJsonFile("appSettings.json", false, false);         }     } }

Для поддержки переменных окружения нужно добавить еще один Nuget-пакет — Microsoft.Extensions.Configuration.EnvironmentVariables, и еще один вызов — .AddEnvironmentVariables():

private static IConfigurationBuilder CreateConfigurationBuilder(string[] args) {     return new ConfigurationBuilder()         .SetBasePath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))         .AddJsonFile("appSettings.json", false, false)         .AddEnvironmentVariables()         ; }

Далее займемся IoC-контейнером. Для этого нам понадобится Nuget-пакет — Microsoft.Extensions.DependencyInjection. Добавим новый метод, который будет создавать и настраивать IoC-контейнер — CreateIocContainer():

using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System.Reflection;   namespace ConsoleAppDI {     internal class Program     {         static void Main(string[] args)         {             var configuration = CreateConfigurationBuilder(args).Build();             var serviceProvider = CreateIocContainer(configuration).BuildServiceProvider();         }           private static IServiceCollection CreateIocContainer(IConfigurationRoot configuration)         {             var services = new ServiceCollection();               return services;         }           private static IConfigurationBuilder CreateConfigurationBuilder(string[] args)         {             return new ConfigurationBuilder()                 .SetBasePath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))                 .AddJsonFile("appSettings.json", false, false)                 .AddEnvironmentVariables();         }     } }

Чтобы не загромождать модуль Program.cs инструкциями по настройке контейнера, ссылками на другие модули приложения и прочим, я рекомендую использовать класс Startup, как это обычно делается в Asp.Net Core приложениях.

Так как я отказался от использования IHost, мне придется реализовать метод расширения .UseStartup<TStartup>(), который за нас уже реализовали для стандартных классов, имплементирующих интерфейс IHost.

Добавим в проект папку Extensions, и затем, добавим в нее класс расширений — ServiceCollectionExtensions.

using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection;   namespace ConsoleAppDI.Extensions {     public static class ServiceCollectionExtensions     {         private const string ConfigureServicesMethodName = "ConfigureServices";           public static IServiceCollection UseStartup<TStartup>(this IServiceCollection services, IConfiguration configuration)             where TStartup : class         {             var startupType = typeof(TStartup);             var cfgServicesMethod = startupType.GetMethod(ConfigureServicesMethodName, new Type[] { typeof(IServiceCollection) });             var hasConfigCtor = startupType.GetConstructor(new Type[] { typeof(IConfiguration) }) != null;             var startup = hasConfigCtor                         ? (TStartup)Activator.CreateInstance(typeof(TStartup), configuration)                         : (TStartup)Activator.CreateInstance(typeof(TStartup), null);               cfgServicesMethod?.Invoke(startup, new object[] { services });               return services;         }     } }

Из приведенного выше кода видно, что в класс добавлен обобщенный метод UseStartup(), обобщенный параметр принимает любой класс. Под капотом метод пытается найти у класса-параметра метод с именем ConfigureServices и выполнить его.

Кроме того, метод анализирует конструктор переданного класса и проверяет, принимает ли конструктор параметр типа IConfiguration. Эта информация используется при инстанцировании класса TStartup. Таким образом, мы сможем передать полученную на предыдущем этапе конфигурацию приложения в экземпляр класса TStartup и использовать ее во время конфигурирования сервисов IoC-контейнера.

Теперь добавим класс Startup. Класс должен содержать метод ConfigureServices принимающий единственный параметр IServiceCollection. Я также добавил конструктор, принимающий IConfiguration.

using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection;   namespace ConsoleAppDI {     internal class Startup     {         public Startup(IConfiguration configuration)         {             Configuration = configuration;         }           public void ConfigureServices(IServiceCollection services)         {           }           public IConfiguration Configuration { get; }     } }

Теперь мы можем использовать наш Startup и созданный ранее метод расширения .UseStartup<T>() для настройки IoC-контейнера:

using ConsoleAppDI.Extensions; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System.Reflection;   namespace ConsoleAppDI {     internal class Program     {         static void Main(string[] args)         {             var configuration = CreateConfigurationBuilder(args).Build();             var serviceProvider = CreateIocContainer(configuration).BuildServiceProvider();         }           private static IServiceCollection CreateIocContainer(IConfigurationRoot configuration)         {             var services = new ServiceCollection()                             .UseStartup<Startup>(configuration)                             ;               return services;         }           private static IConfigurationBuilder CreateConfigurationBuilder(string[] args)         {             return new ConfigurationBuilder()                 .SetBasePath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))                 .AddJsonFile("appSettings.json", false, false)                 .AddEnvironmentVariables();         }     } }

Добавим в проект интерфейс IApplicationRunner с единственным общедоступным методом Run(). Этот интерфейс понадобится для регистрации класса ApplicationRunner, который мы добавим чуть позже, в контейнере IoC.

namespace ConsoleAppDI {     internal interface IApplicationRunner     {         void Run();     } }

Теперь добавим в проект класс ApplicationRunner, который будет реализовывать объявленный выше интерфейс. Этот класс будет содержать логику нашего приложения.

namespace ConsoleAppDI {     internal class ApplicationRunner: IApplicationRunner     {         public void Run()         {             Console.Clear();               Console.WriteLine($"Hello from {nameof(ApplicationRunner)}");         }     } }

Зарегистрируем класс в методе ConfigureServices() класса Startup:

using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection;   namespace ConsoleAppDI {     internal class Startup     {         . . .           public void ConfigureServices(IServiceCollection services)         {             services.AddTransient<IApplicationRunner, ApplicationRunner>();         }           . . .     } }

И, наконец, мы можем получить экземпляр нашего класса от сервис-провайдера. Метод Main() нашего консольного приложения будет выглядеть следующим образом:

static void Main(string[] args) {     var configuration = CreateConfigurationBuilder(args).Build();     var serviceProvider = CreateIocContainer(configuration).BuildServiceProvider();     var runner = serviceProvider.GetRequiredService<IApplicationRunner>();     runner.Run(); }

Результат выполнения нашего приложения показан на скриншоте ниже:

Добавим чтение конфигурации. Не зря же мы добавляли поддержку конфигурации в приложение? 😉

Разработчики .Net Core здорово потрудились, добавив возможность читать конфигурацию в формате JSON. Теперь добавлять секции и ключи в конфигурационные файлы гораздо проще, чем это было во времена классического .Net и конфигурации в формате XML.

Теперь каждая секция конфигурации во время выполнения приложения может быть представлена POCO-классом, т.е. обычным классом C#.

Добавим класс AppSettings, который будет предоставлять доступ к значениям из конфигурационного файла. Добавим в класс единственное строковое свойство — HelloTemplate.

namespace ConsoleAppDI.Config {     internal class AppSettings     {         public string HelloTemplate { get; init; }     } }

Чтобы зарегистрировать наш класс в Startup, нам понадобится подключить пакет Microsoft.Extensions.Options.ConfigurationExtensions.

Класс AppSettings нужно зарегистрировать в IoC-контейнере следующим образом:

services.Configure<AppSettings>(Configuration.GetSection(nameof(AppSettings)));

Далее, чтобы получить доступ к конфигурации приложения из класса ApplicationRunner, нужно добавить в конструктор класса параметр IOptions<AppSettings>, как показано ниже:

using ConsoleAppDI.Config; using Microsoft.Extensions.Options;   namespace ConsoleAppDI {     internal class ApplicationRunner: IApplicationRunner     {         private readonly IOptions<AppSettings> options;           public ApplicationRunner(IOptions<AppSettings> options)         {             this.options = options;         }           . . .     } }

Используем шаблон приветственного сообщения из конфигурации взамен литерала:

using ConsoleAppDI.Config; using Microsoft.Extensions.Options;   namespace ConsoleAppDI {     internal class ApplicationRunner: IApplicationRunner     {         private readonly IOptions<AppSettings> options;           public ApplicationRunner(IOptions<AppSettings> options)         {             this.options = options;         }           public void Run()         {             var greetingMessage = options.Value.HelloTemplate.Replace("{{app}}", nameof(ApplicationRunner));               Console.Clear();               Console.Title = "IoC Console App";             Console.WriteLine(greetingMessage);             Console.WriteLine("Press Enter to exit the application");             Console.ReadLine();         }     } }

Чтобы все заработало, нужно в файл appSettings.json добавить JSON-объект, соответствующий нашему классу AppSettings:

{   "AppSettings": {     "HelloTemplate": "Hello from {{app}}!"   } }

Заключение

Мы добавили в приложение поддержку конфигурационных файлов, а также выполнили настройку контейнера IoC.

Что нам это даёт? Если посмотреть на код модуля Program.cs, то он остался достаточно лаконичным, метод Main() содержит всего четыре строки кода. Код, выполняющий настройку IoC-контейнера вынесен в отдельный класс Startup.

Ну а далее, мы можем дополнять приложение новыми классами, используя внедрение зависимостей через параметры конструктора, при этом основной модуль Program.cs не будет изменяться.

На этом все.

Исходный код можно скачать по следующей ссылке:
Bitbucket / consoleappdi.example


ссылка на оригинал статьи https://habr.com/ru/company/itq_group/blog/719608/