Русский
Русский
English
Статистика
Реклама

It-стандарты

С чего начинается DevOps и куда он может привести

27.05.2021 10:19:54 | Автор: admin

Возможно, вы уже умеете писать отличный код. И может, у вас уже есть реальное представление, как работает платформа, виртуализация и сеть с безопасностью. Но что, если вы не хотите углубляться ни в одну из этих областей? А может, вы уже думали о переходе в DevOps, где требуется много знаний и со стороны dev, и со стороны ops, но не нужно становиться хардкорным разработчиком? Тогда у нас хорошая новость начинать в DevOps можно в любом возрасте и с любой технической специализацией.

Тому пример Александр Шуляк, который нашел себя именно в Девопсе. Накануне конференции DevOps 2021 мы встретились с Сашей и поговорили о том, как и с чего начался его DevOps, а также к чему он пришел в этой карьере.

Саша, очень приятно с тобой познакомиться. На странице про твой доклад написано, что ты делал и делаешь DevOps в больших и маленьких компаниях. Расскажи, как ты начинал.

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

Правда, со временем я всё больше понимал, что ни одна из dev- и ops-областей меня полностью не устраивает. Мне хотелось совместить все эти интересные штуки из разработки и operations вместе. Но тогда я еще не знал, что это возможно в DevOps.

Как ты узнал про DevOps?

В 2016 году в Минске, где я тогда жил, DevOps только набирал обороты, и вакансий в городе было не очень много. Но когда я наткнулся на одну из них, то понял, что это то самое комбо, которое я хотел! И я начал искать именно девопс-вакансии, одновременно изучая видео на ютубе и статьи на хабре, чтобы понимать основы коммерческой разработки и узнать какие-то тонкости.

В результате мне повезло оказаться единственным DevOpsом в аутсорсе средних размеров. Меня сразу же отправили на амбразуры проектов и заказчиков. Это было безумно стрессово, но очень эффективно я учился очень быстро, буквально на ходу.

Какие твои навыки тебе тогда потребовались на практике?

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

Тогда от меня требовалось писать код, чтобы автоматизировать всё и вся. При этом нужно было ковыряться в системах, но уже абстрагируясь от железа. Использовать облачные ресурсы, чтобы быстро получать требуемые мощности.

В DevOps пригодятся любые навыки программирования, и начальный язык не так важен, потому что пересесть на профильные python/golang не будет сложным делом.

Что именно нужно уметь кодить DevOps-инженеру?

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

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

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

Shell-скрипты это ведь часть работы в терминале. Что-то еще там нужно уметь?

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

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

Основные инструменты для сбора метрик сейчас это Prometheus и Grafana. Prometheus это метрик-коллектор (формально time-series database). Как альтернатива мне ещё очень нравится TICK стек на базе InfluxDB. Grafana, в свою очередь, используется для отрисовки красивой инфографики и отправки оповещений.

Для сбора логов в одном месте можно посмотреть Elastic Stack. Он довольно сложный, но дает отличное представление о работе с логами. У него есть бесплатная версия, и этого достаточно, чтобы поиграться с системой и понять, как она работает, из каких компонентов состоит. Альтернативы Elastic Stack Splunk, Datadog. Но это больше enterprise-инструменты, изучать их достаточно сложно.

Что насчет операционных систем? Чем тут заняться, чтобы приблизиться к девопсу?

Из моего опыта программные стеки на Linux намного популярнее, чем на Windows. Изучение можно начинать с любого семейства Linux в целом их архитектура очень схожа.

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

У Linux Professional Institute (LPI) есть статьи по работе linux и базовым манипуляциям с системой. Это открытые курсы/уроки, и они хорошо помогут разобраться с работой Linux. А у Роберта Лава (Robert Love) есть отличная, хоть и немного скучная книга Ядро Linux: описание процесса разработки. Помогает быстро уснуть :)

Ещё в изучении Linux вам может сильно помочь Youtube-канал Кирилла Семаева.

Поговорим про сетевую сторону operations. Что нужно уметь делать здесь?

Первое и самое важное знать как работает сеть. Теоретическая и практическая часть прекрасно описаны в цикле статей от linkmeup сети для самых маленьких. Статьи на примере Cisco, с прекрасными иллюстрациями и отличными объяснениями. Очень легко понять, как сеть работает на всех уровнях.

Ещё в любом случае надо знать веб-сервера, но тут достаточно изучить nginx на базовом уровне. Основные принципы не сильно отличаются от сервера к серверу, а nginx один из самых популярных из них.

Расскажи про принципы DevOps. Это что-то as Code. Как они работают?

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

Наверное, самый популярный инструмент управления инфраструктурой (Infrastructure as Code) это Terraform. Его довольно просто изучать, там великолепная документация. И буквально в этом году вышло новое издание книги Евгения Брикмана Terraform. Инфраструктура на уровне кода, которая тоже отлично объясняет, как работать с этим инструментом.

Есть ещё принцип Configuration as Code, который описывает состояние операционной системы. Тут я советую для изучения Ansible. Можно Chef, но выбрать можно любой, так как поняв основной принцип работы одного, переходить на другие инструменты будет несложно.

А Pipeline as Code вообще очень интересная вещь. Так как синтаксис и предоставляемые возможности инструментов очень схожи, то можно спокойно выучить один и пользоваться всеми. С другой стороны, практически всегда построение пайплайнов приводит к shell-скриптам, потому что основного инструмента без его кастомизации в любом случае будет недостаточно.

Оркестрация это тоже необходимый навык?

Да, примерно по тем же причинам, почему мы используем всё as Code. Когда у вас контейнеров больше одного, ими сложно управлять. Для этого и существуют оркестраторы вроде Mesos, Nomad, Openshift, Kubernetes и так далее. Самый популярный, конечно, Kubernetes. Он достаточно сложный для изучения с точки зрения архитектуры и управления, но базовые понятия выучить не проблема. На первых порах этого должно быть достаточно, а остальное придёт с опытом и интересом.

Какие есть особенности у специализации DevOps-инженеров?

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

На практике список обязанностей сильно зависит от размера компании. Где-то могут быть большие команды и несколько DevOps-инженеров, которые отвечают за build продукта, релиз, платформу или безопасность и governance облака.

После интенсива в минском аутсорсе я пришел работать в Accenture в Латвии. Это было что-то абсолютно противоположное огромная корпорация, четко поставленные процессы, большие команды, много командировок и общения с заказчиками. Для меня это был очень полезный и новый опыт. Но Рига город небольшой и во многом похож на Минск. IT-рынок также не широк, а мне уже хотелось эмигрировать дальше и не просто так, а ради чего-то нового.

Так я оказался в Лондоне. Сейчас, после полутора лет в Gearset, я Senior SRE в финтех-стартапе Divido. И мой опыт показывает, что в Англии больше верят в узкую специализацию, чем у нас. То есть вам надо знать некоторые предметные области в вашем техническом стеке намного лучше, чем другие. Допустим, если вы Cloud Ops инженер, то у вас будет сильный упор на бизнес-инструменты именно в облаках.

У нас же чаще подразумевается, что человек умеет делать всё.

Твой доклад как раз по этой теме?

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

У меня есть некоторый опыт выступлений на DevOps-конференциях, но мне все равно было немного страшно подаваться у меня было не очень много выходов на публику. Но когда доклад приняли, я понял, что пути назад нет и это даже интереснее. Так что если у вас есть интересная тема подавайтесь даже без опыта выступлений! Вместе с куратором всё получится.

Что ты предпочитаешь, офлайн или онлайн?

Вживую намного больше возможностей пообщаться как со зрителями, так и с другими докладчиками. Я очень хочу пообщаться офлайн с единомышленниками. Хотя авиасообщение между Великобританией и Россией до сих пор закрыто, я ищу билеты с пересадкой. Потому что меня ждет и взаимодействие с аудиторией, и новые контакты, и дискуссии. А такое живое общение намного круче чатов!

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

Разумеется доклад Дмитрия Столярова, я его большой фанат! :) У него всегда можно узнать что-то новое про кубер, с которым я последние два года очень плотно работаю. А также о теоретической части SRE/DevOps, поскольку мне очень интересно, как выстроены процессы в разных компаниях и как они скрещивают методологии с реальной жизнью.

Еще будет интересно послушать Станислава Миллера про то, какие роли могут быть у DevOps-лид в организации. Я изучаю возможности карьерного роста в сторону менеджерских позиций или солюшн-архитектора, поэтому интересно посмотреть, что скрывается за должностями в больших компаниях. Из чужого опыта еще интересно узнать про то, как подружить разные команды у Дмитрия Сугробова.

Ну и конечно, нас ждет извечно актуальная и холиварная для меня тема про SRE человек-оркестр, потому что никто не знает как обозвать человека со специфичным набором навыков и вообще надо ли :)

Саша, спасибо тебе огромное за подробный разговор. Желаем тебе найти билеты в Россию, чтобы встретиться на конференции!

Спасибо и до встречи!

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

Конечно, в онлайн вы не сможете пообщаться со всеми вживую. Но онлайн-формат в этом году больше, чем трансляция. Билеты все еще забронировать, а расписание здесь. Присоединяйтесь к сообществу фанатов DevOps-подхода. До встречи на конференции!

Подробнее..

New IP следующий этап развития Интернета или ужесточение контроля над пользователями

01.05.2021 14:19:19 | Автор: admin
image

В Китае жизнь превратилась в компьютерную игру. Или даже в эпизод Черного зеркала. Там с 01.01.2021 принят новый гражданский кодекс, официально узаконивший Систему социального кредита. Теперь каждому гражданину присваивается стартовый рейтинг в 1000 баллов. Благодаря вездесущим камерам видеонаблюдения, Единый информационный центр анализирует каждого по 160 тысячам различных параметров из 142 учреждений. Если рейтинг больше 1050 баллов, то это образцовый гражданин и маркируется индексом ААА. С 1000 баллов можно рассчитывать на А+, а с 900 на B. Если рейтинг упал ниже 849 это уже мутная личность из категории C, кого запросто могут уволить из государственных и муниципальных структур. Те, у кого меньше 600 баллов попадают в группу D, это сравнимо с чёрной меткой. Люди с рейтингом D не могут устроиться на нормальную работу, им не дают кредиты, не продают билеты на транспорт и даже могут отказать в аренде велосипеда. Для сравнения, человеку с рейтингом А+ велосипед в аренду дадут бесплатно и еще разрешат полчаса кататься на нем без единого юаня. Человек со средним рейтингом С велосипед дадут только под залог в 200 юаней.

В Китае аналогичный принцип ранжирования людей применяют и в Интернете. А компания Huawei решила пойти дальше и разработала новый стек протоколов, с которым провайдеры могут блокировать доступ в Сеть любого пользователя с низким рейтингом.


Вставить свои пять юаней


В марте 2021 года Китай опубликовал свой 14-й пятилетний план экономического развития, включая намеченные следующие шаги в области технологий. В проекте чётко говорится, что Китай и его сетевой гигант Huawei готовятся к тому, чтобы их видение Интернета стало глобальным.

Планы Huawei в отношении 6G и выше делают озабоченность США по поводу 5G ничтожной: Huawei предлагает фундаментальный редизайн Интернета, которое называется New IP, призванный обеспечить внутреннюю безопасность в сети. Внутренняя безопасность означает, что отдельные лица должны зарегистрироваться для использования Интернета, а органы власти могут в любой момент отключить доступ к Интернету отдельного пользователя. Короче говоря, Huawei стремится интегрировать китайские режимы социального кредита, слежки и цензуры в архитектуру Интернета. А по замыслу разработчиков новый протокол выведет интернет на новый уровень и позволит быстрее развивать существующие телекоммуникационные сервисы и внедрять новые, в том числе технологию голографического присутствия.

В New IP реализован специальный алгоритм отключения (killswitch), позволяющий блокировать все данные, поступающие из сети на определенный адрес или с него в сеть. Делать это можно будет в любой момент времени, и это означает, что регуляторы интернета смогут не только моментально отключать неугодные ресурсы, но и блокировать доступ к интернету конкретных людей, в буквальном смысле вычисляя их по IP-адресу. Переход на New IP также может потребовать авторизации и аутентификации как новых интернет-адресов, так и людей, связанных с ними. Другими словами, New IP подразумевает полное отсутствие анонимности и приватности в интернете и напоминает глобальную версию Великого китайского файервола, блокирующего жителям КНР доступ ко многим международным ресурсам.

В США считают, что само предложение о новом IP опирается на несовершенную техническую основу, которая угрожает разбить Интернет на несовместимые, менее стабильные и даже менее безопасные локальные сети: Чтобы избежать тщательного изучения недостатков нового IP, Huawei обошла международные органы по стандартизации, где эксперты могут оспорить технические нюансы предложения. Вместо этого Huawei работала через Международный союз электросвязи (МСЭ), где Пекин имеет большее политическое влияние.

Инженерный совет Интернета IETF и другие органы по стандартизации изучают технические изменения по New IP, и заявили, что преждевременно вносить кардинальные изменения без дополнительной информации и согласия. План Huawei по реструктуризации Интернета на основе спекулятивных вариантов использования противоречит логике управления Интернетом, который постулирует, что изменения должны быть постепенными и основываться на установленных потребностях.

Западные СМИ отмечают, что обращение Huawei к Коммунистической партии Китая (КПК) и МСЭ неудивительно, даже несмотря на то, что юрисдикция МСЭ не включает изменения архитектуры Интернета. Когда дело доходит до управления Интернетом, КПК и другие авторитарные режимы долгое время отдавали предпочтение международным организациям, таким как МСЭ, а не таким как IETF или Международная корпорация по присвоению имён и номеров (ICANN). Учреждениями с участием многих заинтересованных сторон руководят самые разные представители промышленности, гражданского общества и правительства; многосторонние институты предоставляют право голоса только национальным правительствам. На форумах эти представители склонны отдавать предпочтение свободному и открытому Интернету, который ослабляет влияние национальных правительств, многие из которых, скорее всего, будут поддерживать жёстко регулируемый и доступный цензуре Интернет.

А чем плох Старый IP?


Новые технологии движущая сила эволюции Интернета. Голографическая коммуникация и огромное количество постоянно растущих физических и виртуальных объектов в Интернете могут оказать большое влияние на существующий протокол IP. Прежде всего, сеть Интернета вещей (IoT), сотовая сеть, промышленная сеть, спутниковая сеть, и т.д., делают Интернет фрагментированным. Взаимосвязь среди этих сетей для предоставления информации и услуг из одной доступной сети (если разрешено) в другую становится достаточно сложной задачей. Хотя он был разработан для взаимосвязи нескольких региональных академических и военных сетей в 1970-х, текущие протоколы TCP/IP содержат ограничения для взаимодействия. Например, фиксированная длина IP-адреса, либо 32 бита для IPv4, либо 128 бит для IPv6, может не подходить для всех сетей. Сеть IoT обычно запрашивает более короткие адреса для уменьшения потребления энергии, вычислений и памяти. Некоторые промышленные сети даже удаляют заголовок IP, чтобы повысить эффективность коммуникации. Космическая связь вряд ли может использовать существующую стратегию фиксированной IP-адресации, привязку подсети и порта маршрутизатора из-за высокодинамичного перемещения узлов-спутников.

TCP/IP ориентирован на идентификацию физических объектов в привязке к их местоположению, и не рассчитан на идентификацию виртуальных объектов, таких как контент и сервисы. Для абстрагирования сервисов от IP-адресов предлагаются различные механизмы маппинга, которые лишь усложняют систему и создают дополнительные угрозы приватности. Как решение для улучшения доставки контента развиваются архитектуры ICN (Information-Centric Networking), такие как NDN (Named Data Networking) и MobilityFirst, предлагающие использовать иерархическую адресацию, которые не решают проблему с доступном к мобильному (перемещаемому) контенту, создают дополнительную нагрузку на маршрутизаторы или не позволяют установить end-to-end соединения между мобильными пользователями.

New IP имеет три ключевые особенности:

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

New IP имеет следующие преимущества по сравнению с протоколами IPv4 и IPv6:

  • Более быстрое предоставление услуг. Новый IP-адрес позволяет клиенту общаться со своим сервером напрямую без запроса DNS. Запрос DNS занимает до 13% времени загрузки. Следовательно, маршрутизация с учётом служб может обеспечить гораздо более быстрое предоставление услуг за счёт исключения запроса DNS;
  • Поддержка динамического развертывания сервиса/контента. Новый IP работает сервис-ориентированным способом, который заботится о что, а не где. Это отличается от
  • существующей IP-маршрутизации, которая должна знать местоположение идентифицированный IP-адресом.


Абстрактная структура пакета New IP

Заголовок New IP начинается с индикатора полей (FI), который указывает, какие поля инкапсулированы в заголовке. Все остальные поля в заголовке New IP являются необязательными, кроме FI. За FI следует (необязательно) ряд основных полей. В отличие от заголовков IPv4 или IPv6, адрес отправителя и адреса назначения в заголовке пакета New IP имеют переменную длину. Более того, адреса могут быть определены с множественной семантикой. Возможный способ для достижения такой гибкости следует заимствовать методологию CBOR (Concise Binary Object Representation).

Заголовок допускает прикрепление идентификаторов функций (FID, Function ID), применяемых для обработки содержимого пакета, а также привязываемых к функциям метаданных (MDI Metadata Index и MD Metadata). Например, в метаданных могут быть определены требования к качеству сервиса, в соответствии с которыми при адресации по типу сервиса будет выбран обработчик, обеспечивающий максимальную пропускную способность.
В качестве примеров привязываемых функций приводятся ограничение крайнего срока (deadline) для пересылки пакета и определение максимального размера очереди во время пересылки. Маршрутизатор во время обработки пакета будет использовать для каждой функции свои метаданные для вышеприведённых примеров в метаданных будет передана дополнительная информация о крайнем сроке доставки пакета или максимально допустимой длине сетевой очереди.


Пример работы New IP с устройствами умного дома

Поскольку все устройства в доме подключены к одной домашней сети, датчик движения (с адресом 15) может отправлять уведомления на камеру видеонаблюдения (с адресом 16) напрямую со своим внутридоменным адресом. Потому что количество устройств в домашней сети небольшое, можно использовать 8-битные короткие адреса для снижения потребления энергии. Датчик движения отправляет сигналы камере видеонаблюдения только в одном направлении. Следовательно адрес источника может быть опущен для дальнейшего уменьшения пакета и повышения эффективности передачи информации. Перед тем, как камера видеонаблюдения отправить изображение на смартфон хозяина дома, пакеты сначала должны быть переданы на маршрутизатор. Маршрутизатор New IP добавит сегмент адреса 4.3.2.1 к исходному адресу для обратной маршрутизации. Потом, измененные пакеты данных отправляются на смартфон пользователя через интернет.

По сравнению с 6LoWPAN, предлагаемая структура New IP позволяет маршрутизаторам пересылать пакеты данных напрямую на основе короткого адреса, без сжатия и декомпрессии, принятые в 6LoWPAN. Таким образом, New IP может упростить реализацию сетевых узлов, которые особенно ценны для сетей IoT с ограниченными ресурсами.

Без политики никуда



По мнению американских экспертов, авторитарные правительства могут маргинализировать частный сектор работая через многосторонние форумы, такие как МСЭ. Это означает, что МСЭ, естественно, будут более восприимчивы к таким предложениям, как Новый IP, которые предоставляют национальным правительствам больший контроль над Интернетом: Обход традиционных институтов управления Интернетом в пользу МСЭ создаёт прецедент для будущих изменений, связанных с управлением Интернетом, которые будут проходить через МСЭ вместо более сбалансированных институтов с участием многих заинтересованных сторон.
Последние семь лет Китай занимает лидирующие позиции в МСЭ. Во время своего пребывания на посту генерального секретаря МСЭ Хоулинь Чжао (Houlin Zhao) поощрял расширение мандата МСЭ с телекоммуникационного агентства до технологического агентства.


В своем отчете за март 2020 года Комиссия по киберпространству США (Cyberspace Solarium Commission, CSC) подчеркнула то, как правительство США не участвует в международных форумах, таких как МСЭ, и то, как Китай участвует. Фактически, Новый IP стал отчасти результатом предыдущего отказа США от лидерства, поскольку первоначальное расследование необходимости этой новой технологии было инициировано фокус-группой МСЭ, в которой доминировала компания Huawei, но без участия США. Такая асимметрия выходит за рамки этой конкретной фокус-группы. В преддверии ВАСЭ-20 Китай назначил представителей на руководящие должности практически в каждой исследовательской комиссии МСЭ. Даже когда китайские фирмы не получают руководящих должностей, Китай посылает толпы тщательно подготовленных, синхронизированных делегаций, чтобы продвигать стандарты, выгодные для Пекина и его национальных чемпионов.

Представитель США Дорин Богдан-Мартин баллотируется на должность генерального секретаря МСЭ в 2022 году. Даже если Богдан-Мартин не победит на выборах, Соединенные Штаты будут работать над тем, чтобы окончательный победитель прекратил политику Чжао, заключающуюся в том, что МСЭ лоббирует Новый IP.

Кандидат от России Рашид Исмаилов тоже может получить пост генерального секретаря. Исмаилов возглавляет делегацию, которая регулярно пытается усилить власть МСЭ над управлением Интернетом за счет институтов с участием многих заинтересованных сторон. Исмаилов лично выступает за предоставление правительствам и некоммерческим организациям возможности контролировать деятельность ICANN, одного из самых важных органов в управлении Интернетом.

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

Вопреки текущим политическим дебатам, New IP предлагает открытую и свободную дискуссию, приглашая исследователей из всех стран и отраслей по всему миру принять участие в исследовании, которое позволит увидеть, как Интернет будет развиваться в соответствии с требованиями. Новый IP не определяет модели управления для использования этих технологий, и не ведёт к более централизованному нисходящему контролю над Интернетом. При этом мы следуем установленным путям для развития интернет-технологий в стандартных органах, не связанных с конкретным управлением, которое принимают операторы и правительства во всем мире. Это иллюстрируется нашей работой по предотвращению DDoS-атак, которая действительно предлагает так называемый протокол отключения (Shut-off protocol). Эта концепция аналогична предложениям, сделанными, например, учёными Университета Карнеги-Меллона в США, а также найденным в аналогичных технологиях, которые обсуждались, среди прочего, в IETF DDoS Open Threat Signaling (DOTS). Такое отключение используется атакуемой сетью, чтобы сигнализировать исходной сети злоумышленника запрос на предотвращение дальнейшего атакующего трафика. Таким образом, эта технология хорошо зарекомендовала себя в существующих решениях, отметили представители Huawei.

Из-за ограничений, связанных с пандемией COVID-19, Всемирная ассамблея по стандартизации электросвязи (ВАСЭ-20) МСЭ, на которой будет официально обсуждаться New IP, была отложена до февраля 2022 года.





На правах рекламы


VDSina предлагает мощные и недорогие VPS с посуточной оплатой. Интернет-канал для каждого сервера 500 Мегабит, защита от DDoS-атак включена в тариф, возможность установить Windows, Linux или вообще ОС со своего образа, а ещё очень удобная панель управления серверами собственной разработки.

Подробнее..

Транспортный протокол QUIC приняли в качестве стандарта RFC 9000

01.06.2021 02:22:59 | Автор: admin


QUIC новый транспортный протокол связи, который отличается уменьшенным временем задержки, большей надёжностью и безопасностью, чем широко используемый сегодня TCP (RFC 793).

Уже много рассказывалось о преимуществах транспорта QUIC, который взят за основу будущего стандарта HTTP/3. В HTTP следующего поколения транспорт TCP меняется на QUIC, что означает автоматическое ускорение соединений и зашифровку всего интернет-трафика, который раньше шёл в открытом виде по TCP. Нешифрованный QUIC не предусмотрен вообще.

В мае 2021 года состоялось знаменательное событие: протокол QUIC принят в качестве официального стандарта RFC9000. Это великолепные новости для всей интернет-экосистемы.

Утверждением таких стандартов занимается Инженерный совет Интернета (IETF). Ранее были оформлены вспомогательные стандарты RFC 9001, RFC 9002 и RFC 8999.

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

В последние годы QUIC был одним из главных приоритетов IETF. Появившись как эксперимент Google, вскоре разработка QUIC вышла на международный уровень. Она велась почти пять лет. Зафиксировано 26 очных собраний, 1749 задач в трекере и многие тысячи писем в почтовой рассылке.

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

Окостенение означает, что система с каждым годом становится всё менее гибкой, менее подвижной. QUIC принесёт в транспортный уровень множество инноваций, включая обязательное шифрование, версионность, гораздо более богатый и более производительный набор сервисов, поверх которых будут строиться новые технологии. Предполагается, что QUIC приведёт к появлению нового поколения интернет-инноваций. Это уже начало происходит с расширениями, такими как ненадёжные датаграммы (Unreliable Datagram Extension). Ненадёжные датаграммы открывают двери перед новым классом медиа в реальном времени и другими приложениями, которым нужен более функциональный транспорт, чем обязательная доставка пакетов с обрывом канала при потере нескольких пикселей. Мы уже видим многообещающие технологии, такие как MASQUE и WebTransport.

HTTP/3


Стандарт HTTP/3 (это HTTP поверх QUIC) идёт с небольшим опозданием за QUIC и тоже будет официально принят в самое ближайшее время.


34-й (!) драфт HTTP/3

С момента принятия HTTP/2 прошло шесть лет: спецификация RFC 7540 опубликована в мае 2015-го, но пока не используется повсеместно. Протокол реализован во всех браузерах ещё с конца 2015 года, а спустя три года только 45,4% из 10 млн самых популярных интернет-сайтов поддерживают HTTP/2. Два с половиной года назад таких было 31,2%. Севсем недавно на HTTP/2 перешли сайты Amazon, Paypal, Telegram.org.

Cейчас практически готова третья версия HTTP/3, осталось совсем немного подождать.

QUIC представляет собой замену TCP, которая работает поверх UDP. Изначально эта технология была создана инженерами Google, как и предыдущий протокол SPDY, который стал основой HTTP/2. В первое время QUIC именовали HTTP/2-encrypted-over-UDP.

Затем разработку QUIC передали в IETF для стандартизации. Здесь он разделилcя на две части: транспорт и HTTP. Идея в том, что транспортный протокол можно использовать также для передачи других данных, а не только эксклюзивно для HTTP или HTTP-подобных протоколов. Однако название осталось таким же: QUIC. Разработкой транспортного протокола занимается рабочая группа QUIC Working Group в IETF.

Долгое время версия IETF называлась iQUIC, в то время как Google и другие продолжили работу над собственной реализацией gQUIC, но 7 ноября 2018 года один из ведущих разработчиков протокола Дмитрий Тихонов объявил, что стороны достигли совместимости протоколов, и теперь разработка продолжится в общем русле. QUIC в Chrome включается в настройках chrome://flags. Есть ещё расширение-индикатор, которое показывает, какие сайты поддерживают QUIC.



Встроенная безопасность и производительность


В чём преимущества транспортного протокола QUIC перед TCP? Преимуществ очень много. По словам руководителя рабочей группы Марка Ноттингема, переход от устаревшего TCP на новые протоколы просто неизбежен, поскольку сейчас очевидно, что TCP страдает от проблем неэффективности.

Поскольку TCP протокол доставки пакетов по порядку, то потеря одного пакета может помешать доставке приложению последующих пакетов из буфера. В мультиплексированном протоколе это может привести к большой потере производительности, объясняет Марк Ноттингем. QUIC пытается решить эту проблему с помощью эффективной перестройки семантики TCP (вместе с некоторыми аспектами потоковой модели HTTP/2) поверх UDP.

Кроме перехода значительного объёма трафика с TCP на UDP, протокол QUIC требует обязательного шифрования: нешифрованного QUIC не существует вообще. QUIC использует TLS 1.3 для установки ключей сессии, а затем шифрования каждого пакета. Но поскольку он основан на UDP, значительная часть информации о сессии и метаданных, открытых в TCP, шифруется в QUIC.



В статье Будущее интернет-протоколов Марк Ноттингем говорит о значительных улучшениях в безопасности с переходом на QUIC:

На самом деле текущий короткий заголовок iQUIC который используется для всех пакетов, кроме рукопожатия выдаёт только номер пакета, необязательный идентификатор соединения и байт состояния, необходимый для процессов вроде смены ключей шифрования и типа пакета (который тоже может быть зашифрован). Всё остальное зашифровано включая пакеты ACK, что значительно повышает планку для проведения атак с анализом трафика.

Кроме того, становится невозможна пассивная оценка RTT и потерь пакетов путём простого наблюдения за соединением; там недостаточно информации для этого.

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

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

Возможно, принятие стандарта QUIC произошло бы и раньше, если бы компания Google не поспешила внедрить свою реализацию в браузер Chrome, так что случилось раздвоение стандарта.

Тем не менее, прогресс неизбежен и в ближайшие годы обязательно продолжится стандартизация и повсеместное внедрение различных протоколов нового поколения, в том числе HTTP/3 на транспорте QUIC.



См. также:





Отмечайте юбилей GlobalSign и получайте скидки!


Подробнее..

Наша анонимность утрачена?

04.06.2021 22:07:07 | Автор: admin

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

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

1. Ip-адрес. Провайдеры годами хранят статистику на каком ip-адресе работал их пользователь. Зная ip-адрес можно легко вычислить расположение пользователя.

2. DNS-запросы. Каждый раз, когда Ваш браузер хочет получить доступ к определенной службе, например Google, обратившись к www.google.com, Ваш браузер запросит службу DNS, чтобы найти IP-адреса веб-серверов Google. Таким образом, интернет-провайдер DNS-записей сможет рассказать обо всем, что Вы делали в сети, просто просмотрев те журналы, которые, в свою очередь, могут быть предоставлены злоумышленнику.

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

4. Устройства Wi-Fi и Bluetooth вокруг Вас. Производители смартфонов заложили функции поиска Вашего местонахождения без использования GPS-функций. Достаточно сканировать Wi-Fi сети вокруг устройства. Данные о Вашем местоположении отправляются на сервера третьих компаний.

5. Использование Wi-Fi на смартфоне. Чтобы получить Ваши данные хакеры могут использовать специальные устройства, которые будут мешать работе wi-fi точек доступа и вынуждать Ваш смартфон подключиться к их устройству вместо публичной wi-fi точки доступа. В этом случае все Ваши данные становятся доступными для злоумышленника. В данном случае используются технологии MITM (Man-In-The-Middle) или человек посередине.

6. Использование Tor/VPN. За прошедшие годы было разработано и изучено множество передовых методов деанонимизации зашифрованного трафика Tor. Атака по корреляционным отпечаткам пальцев: эта атака будет отпечатывать ваш зашифрованный трафик (например, веб-сайты, которые вы посещали) только на основе анализа вашего зашифрованного трафика (без его расшифровки). Он может сделать это с колоссальным успехом в 96%. Такие отпечатки пальцев могут использоваться злоумышленником, имеющим доступ к вашей исходной сети (например, Ваш интернет-провайдер), для выяснения некоторых ваших зашифрованных действий (например, какие веб-сайты вы посещали).

7. Современные смартфоны на Android, IOS.
После выключения такого устройства оно будет продолжать передавать идентификационную информацию на близлежащие устройства даже в автономном режиме с использованием Bluetooth Low-Energy. Это дает способ найти Вас даже если Ваш телефон выключен, но имеет подключенный аккумулятор.

8. IMEI идентификатор Вашего оборудования. IMEI привязан непосредственно к телефону, который вы используете. Этот номер известен и отслеживается операторами мобильной связи, а также известен производителями. Каждый раз, когда ваш телефон подключается к мобильной сети, он регистрирует IMEI в сети. Он также используется многими приложениями (например, банковскими приложениями, злоупотребляющими разрешением телефона на Android) и операционными системами смартфонов (Android/IOS) для идентификации устройства. Сегодня предоставление вашего реального номера телефона в основном то же самое или лучше, чем предоставление вашего паспорта. Журналы антенн оператора мобильной связи также хранят некоторые данные о подключении. Они знают и регистрируют, например, что телефон с IMEI, подключен к набору мобильных антенн, и насколько мощный сигнал каждой из этих антенн. Это позволяет легко выполнять триангуляцию/геолокацию сигнала. Они также знают, какие другие телефоны (например, ваш настоящий) подключены в одно и то же время к тем же антеннам с тем же сигналом, что позволит точно знать, что этот телефон всегда был подключен в том же месте и в то же время, что и этот другой телефон, который появляется каждый раз, когда используется записывающий телефон. Эта информация может использоваться различными третьими сторонами для точного определения вашего местоположения/отслеживания.

9. Ваш браузер. При посещении любых сайтов ваш браузер получает уникальные cookie-данные с каждого сайта. Ваши данные в браузере становятся уникальными, а это значит, что веб-порталы знают кто зашел через браузер. На смену cookies приходят supercookies и Ваша анонимность сводится практически к нулю.

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

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

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

При повышении количества собранных данных формируется цифровой профиль человека, которые содержат в себе:

  • пол;

  • возраст;

  • семейное положение;

  • политические, религиозные взгляды;

  • финансовое состояние;

  • интересы;

  • привычки;

  • и многие другие.

Согласно результатам исследования EFF (Electronic Frontier Foundation), уникальность отпечатка браузера очень высока и он содержит в себе ниже описанные данные:

  • User-agent (включая не только браузер, но и версию ОС, тип устройства, языковые настройки, панели инструментов и т.п.);

  • Часовой пояс;

  • Разрешение экрана и глубину цвета;

  • Supercookies;

  • Настройки куки;

  • Системные шрифты;

  • Плагины к браузеру и их версии;

  • Журнал посещений;

  • И другие данные.

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

Согласно исследованию Browser Fingerprinting via OS and Hardware Level Features, точность идентификации пользователя при помощи отпечатка браузера составляет 99,24%.

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

Статья написана в соавторстве:
1. Меньшиков Ярослав
2. Беляев Дмитрий

Подробнее..

Мобильные контейнеры для раздельного хранения данных

07.06.2021 12:06:42 | Автор: admin

Работодатели уже привыкли к тому, что можно не возмещать затраты со.

Но и эта медаль двухсторонняя. Сотрудники требуют гарантий, что работодатель не читает их переписку или не смотрит их фотографии. Работодатели в свою очередь против того, чтобы сотрудники делились корпоративными документами в социальных сетях или передавали их в СМИ.

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

Зачем нужен контейнер работодателям и их сотрудникам?

Работодатели и сотрудники хотят, чтобы контейнер защищал ИХ секреты. Только секреты каждой из сторон находятся по разные стороны контейнера секреты работодателя находятся внутри контейнера, а секреты сотрудника снаружи.

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

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

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

Особенность контейнеров для iOS

В своей прошлой статье мы убеждали читателя, что iOS это закрытая экосистема, которую нужно принимать такой, какая она есть. Контейнеры на iOS ещё одно тому подтверждение.

С точки зрения контейнеризации в iOS есть встроенный механизм разделения корпоративного и личного. Apple называет корпоративное управляемым (managed), а личное неуправляемым (unmanaged).

Управляемыми в iOS могут быть приложения, учётные записи и URL в Safari. С помощью встроенных политик можно запретить передачу данных между управляемым и неуправляемым, но только случайную. Это значит, что сотрудник не может передать вложение из корпоративной почты в личную почту или в WhatsApp, но может скопировать текст вложения и вставить его куда угодно!

Apple считает, что защититься от преднамеренной утечки данных невозможно, поэтому решил позаботиться о своих сознательных пользователях и не дать им случайно допустить утечку

Если компания решает, что встроенных механизмов безопасности iOS для нее недостаточно, ей приходится реализовывать дополнительные механизмы защиты в корпоративных приложениях. Например, блокируя в них возможность доступа к буферу обмена. Сделать это проще всего с помощью SDK разработчиков систем управления мобильностью, например, SafePhone.

Разнообразие Android - контейнеров

Android исторически предоставляет больше возможностей для контейнеризации.

Первой компанией, которая сделала возможным создание контейнеров на Android, стала компания Samsung. В 2012 году на смартфоне Samsung Galaxy S3 впервые стали доступны функции корпоративной платформы безопасности Samsung Knox. В частности, Knox контейнеры. Большинство современных устройств Samsung также их поддерживают. Многие функции платформы Samsung Knox бесплатны, но функции Knox контейнеров были платной опцией. Позже Google анонсировал свою бесплатную корпоративную платформу Android for Enterprise c меньшим набором функций.

С годами число функций управления контейнерами, которые были эксклюзивно доступны на устройствах Samsung, сокращалось, потому что они появлялись у Google. В результате, начиная с
1 июля 2021 года, Samsung принял решение о бесплатном предоставлении возможностей Knox-контейнеризации. В составе платформы Samsung Knox ещё остаются платные опции, которых нет у Google. Например, корпоративных сервис обновления прошивок мобильных устройств E-FOTA One, о котором мы рассказывали в одной из прошлых статей.

Но конкретно Knox контейнеры отныне бесплатны.

Контейнер в Android или, как его называет Google, рабочий профиль выглядит для пользователя как отдельная папка или отдельный рабочий стол, где размещаются корпоративные приложения. Приложения в контейнере работают так, как будто за пределами контейнера ничего не существует. В контейнере есть свой буфер обмена, своя виртуальная память для хранения файлов и т.д.

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

Вроде то, что нужно? Да, но не обошлось без важных особенностей.

В составе Samsung Knox есть клиентские библиотеки для Android, с помощью которых можно разработать клиент управления, который сам создаст контейнер, применит в нём необходимые политики безопасности и наполнит его приложениями.

Работает эта схема так:

  1. На мобильное устройство устанавливается клиент управления.

  2. Пользователь регистрирует устройство на сервере управления.

  3. Клиент управления создаёт и настраивает контейнер для работы. После чего периодически спрашивает у сервера управления, не изменились ли эти настройки.

  4. Можно доставить обновления настроек быстрее с помощью push-уведомлений от Google, но их использование необязательно.

Преимущество этой схемы в том, что её можно построить в локальной инфраструктуре заказчика (on-premise). Для крупного бизнеса в России это важно.

У платформы Android for Enterprise от Google тоже есть клиентские библиотеки и с их помощью можно управлять устройствами без контейнеров устанавливать приложения, настраивать ограничения и т.д. Даже можно создать контейнер, поместить в него встроенный Gmail или Google Chrome и запретить сотруднику копировать из контейнера файлы. Всё это будет работать on-premise.

Но клиентские библиотеки Google не помогут, если нужно разместить в контейнере приложение собственной разработки или какое-то приложение из Google Play. В этом случае необходимо использовать Android Management API, который работает по несложной схеме:

  1. На мобильное устройство устанавливается клиент управления от Google Android Device Policy.

  2. Администратор создаёт настройки контейнера какие приложения в него установить, какие политики ограничений применить и т.д.

  3. Сервер передаёт настройки контейнера в Google с помощью Android Management API. Дальше Google обеспечивает их применение на устройстве самостоятельно. При этом все команды и все дистрибутивы корпоративных приложений нужно передать в Google.

    Источник: https://developers.google.com/android/management/introductionИсточник: https://developers.google.com/android/management/introduction

Похожим образом устроено управление iOS, но в случае с iOS корпоративный сервер управления передаёт в Apple только уведомления о наличии команды. Далее устройство забирает команды и дистрибутивы приложений с корпоративного сервера, а не с сервера Apple.
Возможно, Google хотел создать более удобную технологию управления, чем у Apple, но не все компании готовы мириться с тем, что Google знает, какие настройки безопасности и какие команды управления они сообщают своим мобильным устройствам. Ведь это создаёт риск того, что команды могут быть изменены или вовсе не доставлены.

Корпоративный Android в личном пользовании

Многие компании, которые покупают сотрудникам мобильные устройства для работы, разрешают также использовать их в личных целях. В этом случае тоже нужны контейнеры, чтобы разделить корпоративные и личные данные. Если вы планируете реализовать такой сценарий, учтите, что, начиная с Android 11, у этого сценария есть принципиальные ограничения.

Начиная с Android 11, нельзя одновременно управлять и контейнером, и тем, что находится вне его. Это сделано, чтобы исключить доступ работодателей к личным данным сотрудников.
Цена приватности оказалась достаточно высокой. Теперь на корпоративных устройствах с контейнером нельзя определять геолокацию, устанавливать приложения вне контейнера и проверять устройство на наличие вирусов.

Источник: https://docs.samsungknox.com/admin/knox-platform-for-enterprise/work-profile-on-company-owned-devices.htmИсточник: https://docs.samsungknox.com/admin/knox-platform-for-enterprise/work-profile-on-company-owned-devices.htm

В качестве альтернативы Samsung предложил оригинальную технологию Knox Separated Apps. Технология позволяет создать на корпоративных устройствах контейнер для личных приложений. Работодатель управляет всем устройством и не получает доступа к данным сотрудника в личном контейнере. А приложения в личном контейнере не получают доступа к корпоративным данным, поэтому с их помощью нельзя реализовать утечку информации.

Knox Separated Apps, как и Knox контейнеры, с 1 июля 2021 года также станет бесплатной.

Советы для топ-менеджеров

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

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

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

На каждом новом устройстве корпоративный софт не работает совершенно особенным образом. Каждая мажорная версия Android c 4 по 12 серьёзно отличаются. У каждого производителя своя сборка Android. У каждой сборки Android, особенно китайской, свои тараканы неуправляемые менеджеры памяти и батареи, которые так и норовят поскорее закрыть приложение или не дать ему вовремя получить данные от сервера, дополнительные разрешения, которые пользователь должен вручную дать приложению и которые он может в любой момент отобрать и т.п.

Если планировать мобилизацию компании на 3-5 лет вперёд, дешевле выбрать несколько моделей устройств, и дальше проверять и разрабатывать корпоративный софт (клиент документооборота, приложения с BI-отчётностью, мессенджеры и т.п.) на этих конкретных моделях. Всё-таки корпоративный софт пишут не тысячи разработчиков Facebook по всему миру. Поэтому чем меньше вариативность устройств, тем меньше ошибок, тем меньше число уязвимостей и ниже вероятность их успешной эксплуатации. Короче, всем удобнее и безопаснее.

Если у вас возникли вопросы или сомнения после прочтения статьи, напишите о них в комментариях.

Подробнее..

Демократия в Telegram-группах

07.05.2021 14:19:42 | Автор: admin

Многие из нас проводят время в профильных телеграм-группах. Власть над общением здесь принадлежит случайным людям со своими недостатками. Нередко встречаются конфликты и злоупотребления. Это побуждает задуматься, а можно ли поддерживать порядок иначе, так, чтобы не расцветал мошеннический спам и одновременно ни у кого не было абсолютной власти над адекватным собеседником?
И в моем случае эти размышления вылились в разработанную и протестированную систему которую уже сегодня можно подключить в ваш Telegram.

Прежде всего, нужно определить что является ключевым аспектом, валютой системы. Не карма и не баллы, не лайки и не рейтинг. Им стало само время. Что из этого следует?

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

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

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

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

Итак, как это работает в теории разобрались, а что необходимо для практического функционирования такой системы?

  • Простой способ подключения чата к системе.
    - Реализована в виде бота

  • Максимально удобный для Telegram команд UX
    - Есть распознавание речи основанное на нормализованных семантических представлениях

Где примеры использования?

Бот понимает в запросах и русский и английский язык в свободной форме. Используются сокращения: d - дни, h - часы, m - минуты, s - секунды. Все уведомления публичны, но исчезают через 15 секунд, чтобы не засорять общий чат.

Вот как можно посмотреть сколько времени накопилось. Вот как можно посмотреть сколько времени накопилось. Забанить токсичного человека, спамера или мошенника можно указав в ответе в ему, в свободной форме, на сколько времени он получает бан (и за что по желанию). Забанить токсичного человека, спамера или мошенника можно указав в ответе в ему, в свободной форме, на сколько времени он получает бан (и за что по желанию). Если это было недопонимание и человек все же хороший, можно таким же образом, просто написать в ответе что его нужно разблокироватьЕсли это было недопонимание и человек все же хороший, можно таким же образом, просто написать в ответе что его нужно разблокироватьЧтобы перевести время другому пользователю указажите в ответе сколько времени нужно передать.Чтобы перевести время другому пользователю указажите в ответе сколько времени нужно передать.

Довольно слов, покажите мне код!

Для бекенда использовался язык Kotlin + JVM, в качестве базы данных используется Redis-кластер. Весь код продокументирован и доступен на GitHub: demidko/timecobot
Чтобы начать использовать бота в вашей телеграм-группе просто добавьте его с правами администратора: @timecbobot

Напишите пожалуйста свое мнение в комментариях, нужное ли это для сообщества дело и стоит ли развивать систему дальше? Что можно улучшить или поменять? Интересна ли подробная статья с кодом на тему как это реализовано внутри?

Всем удачного дня!

Подробнее..

Монтажный шкаф для ЦОД. Критерии выбора. Часть 2 оптимальная комплектация и возможности кастомизации

11.05.2021 12:14:21 | Автор: admin

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

Нужна ли шкафу дверь?

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

Перфорировать или нет?

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

Какая несущая способность шкафа вам нужна?

Несущая способность бывает статической и динамической. Статическая определяет нагрузку на неподвижный шкаф. Не поддавайтесь на уговоры приобрести модель, выдерживающую до 1500 и даже 2000 кг просто потому, что такой нагрузки не бывает, а если не бывает то зачем платить лишние деньги? 1000 кг более чем достаточно для стандартной эксплуатации в ЦОД. Динамическая нагрузка важна для только тех, кто перемещает загруженные оборудованием стойки внутри машзала. Если вы так не делаете, то нет не обращайте особо внимание на этот показатель.

Что такое оптимальная комплектация?

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

  • Одностворчатую переднюю дверь и двухстворчатую заднюю (чтобы уменьшить зону обслуживания сзади);

  • Регулируемые ножки (установить шкаф на нужную высоту) и ролики в комплекте (чтобы отвезти до места установки);

  • Изоляцию переднего фронта шкафа по периметру (чтоб избежать утечек воздуха);

  • Кабельные вводы в крыше со щеточным краем или другой защитой от утечки воздуха (в задней части для установки БРП, в передней или средней для слаботочной коммутации);

  • Вертикальные монтажные панели (для установки БРП и аксессуаров);

  • Комплект объединения в ряд;

  • Поставку в сборе на паллете (чтобы не отнимать у заказчика время на сборку!).

Кастомизация и аксессуары

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

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

Хорошим тоном со стороны поставщика считается добавление к поставке крепежа и инструментов для установки оборудования.

Сервис

Сервисные услуги в сегменте монтажных шкафов ориентированы на облегчение и ускорение развертывания шкафов в больших дата-центрах. Помимо стандартной доставки в комплекс услуг могут включаться:

  • разгрузка;

  • распаковка;

  • транспортировка до машзала;

  • расстановка и сборка в ряды;

  • утилизация упаковки;

  • установка 19профилей на нужной глубине;

  • монтаж аксессуаров на определённый юнит;

  • закрепление блоков распределения питания и т. д.

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

Подробнее..

Есть будущее у Fullstack-разработчиков?

05.06.2021 16:05:21 | Автор: admin

"Неужели компании хотят так сильно экономить, что готовы терять в качестве и времени?"

Решил поделиться своим опытом, который достаточно тесно связан с Fullstack-разработчиками, в одном стартап (хотя бьются на рынке с 2016 года).

Сразу прокомментирую, что в этой статье нет цели оклеветать или высказать своё негативное мнение о компаниях. Нет! Я опираюсь только на их опыт и на полученные результаты.

Я занимаюсь подбором IT-специалистов и для того, чтобы не быть "тем самым HR, который сливает , а не помогает, своими оценочными тестами и вопросами вне понимания специфики работы", мне приходится изучать гигабайты информации на habr и других ресурсах. И в первых рядах моего несогласия, есть такая профессия - Fullstack-разработчик.

Немного для общего понимания поясню, почему я выбрал подход собирать информацию об IT-специалистах.

С 2018 года я начал вникать в эту сферу более плотно. Освоил основы HTML/CSS, познакомился с Python, PHP, Swift. Естественно эти познания подтолкнули меня сменить компанию из обычной на IT. Мне повезло и меня взяли в достаточно перспективный на мой взгляд стартап (разглашать не буду его название из добрых побуждений). Первые месяца три, я работал на должности специалиста по работе с клиентами, но сейчас понимаю, что на самом деле выполнял функционал Project-manager и одновременно Product Owner. Ну и по совместительству еще продавец и support.

Мне реально нравился проект и я горел его улучшить. Хотите верьте, хотите нет, но в этом проекте я стал хуже спать. Я постоянно думал, что можно улучшить. Я стал предлагать идеи по улучшению своему непосредственному, а тот вообще не про IT и очень скоро я понял, что я ему говорю свои идеи, а он просто не правильно их "продает" генеральному. Я не хочу сказать, что этот руководитель плохой. Наоборот, он достаточно внимательно относился ко всем сотрудникам и реально хотел донести мои идеи генеральному, но просто не владея техническим восприятием, он не мог объяснить так, как это говорил ему я.

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

Генеральный оценил мой подход и что больше радовало, мои предложения. Совсем скоро меня утвердили уже как project-manager, а еще пол года спустя, назначили техническим директором. Но для меня эти статусы были не важны. Я хотел менять и я менял.

И вот мне все же пришлось упереться в стену, которую непроизвольно построили разработчики. Сейчас вы поймете о чем я. Проработав почти год в проекте и коммуницируя с Team Lead, я не знал, сколько в команде разработчиков. Мне пояснили, что проект новый на рынке (хотя я знал точно, что они не уникальны) и что не могут себе позволить разработчиков со стороны. Что есть команда, (как позже я все же выяснил, что она из 5 человек), в которой есть back&front и парочка как раз Fullstack-разработчиков. На них и держался весь проект.

Естественно они сильные специалисты и я и сейчас в шоке, как они все это стойко держали. Да, Scrum (Agile), Jira. Пользовались теми же инструментами, которые хвалил рынок. Но "бэклог" еженедельно рос. Спрос на продукт стремительно набирал обороты и я начал "кричать", пытаясь быть услышанным, что нам срочно нужно расширять команду разработчиков и причем принципиально , среди них не должны быть больше Fullstack. К тому моменту, когда негодование users начинало зашкаливать, из-за постоянных срывов обещанных дедлайнов, я явно видел, что для быстрого роста и своевременного исправления скопившихся багов, нужно брать людей на отдельные блоки. И вот тут-то мы и выяснили, что Fullstack-разработчики писали код так, что его нельзя пока что разделить на блоки. Что если пустить со стороны человека, то он будет видеть весь код. Увы, но такова была реальность. Приняли решение максимально срочно декомпозировать, но вы наверно знаете, что на практике это совсем не просто.

"Страсти" в этом проекте накалялись. Разработчики сутками пытались исправлять баги, про которые ежедневно менеджерам по работе с клиентами звонили клиенты. Все мы принимали еженедельно новые алгоритмы, которые полностью меняли структуру работы и максимально выводили из процесса разработчиков (я их нарисовал 5 в период 7 месяцев). Пытались максимально разгрузить разработчиков, сняли все, что можно получить временно внешними ресурсами (сайт на Битрикс, CRM и так далее). Но в итоге, это не дало нужных результатов. Спустя 2 года, я покинул проект.

И вот сейчас, находясь в поисках IT-специалистов для заказчиков, я все чаще вижу вакансию Fullstack-разработчик. Неужели компании хотят так сильно экономить, что готовы терять в качестве и времени?

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

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

Успешных вам проектов!

Подробнее..

Перевод Что такое machine learning?

29.04.2021 12:05:53 | Автор: admin

Данный пост содержит выдержки из одноименной статьи Дэниела Фагеллы, руководителя отдела исследований в компании Emerj от 26.02.2020. Дэниел является всемирно востребованным экспертом по последствиям ИИ по направлению конкурентных стратегий для лидеров бизнеса и государств; его услугами пользуются ООН, Всемирный банк, Интерпол и ведущие компании.

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

Главный тезис указанного поста звучал так:

Мы имеем феномен, который называется усвоением знаний человеком и животными. Этот феномен объясняется теориями усвоения знаний (в частности павловской теорией условных-безусловных рефлексов). В 60-х годах XX-го века компьютерные ученые задались вопросом о том, как создать самообучающуюся машину, и дали классическое определение такой машины (определение дано выше в посте), как способной автоматически усваивать знания из данных, не будучи для этого программируемой. То есть признавалось, что вычислительную машину, в отличие от людей и животных, которые наделены такой способностью по природе, надо еще наделить способностью усваивать знания. Это делается путем строительства специальных моделей машинного усвоения знаний, в основе которых лежит алгоритм машинного усвоения. Строительство таких моделей и алгоритмов и является предметом подобласти ИИ под названием машинное усвоение (МУ).

Приведенный ниже перевод сделан с учетом именно такого понимания термина machine learning. Если вы настроены к такому пониманию , как говорится по-аглицки, upfront враждебно то прошу не тратить своего времени на мои призывы подумать о присоединении к принятому во всем мире пониманию machine learning как машинному (автоматическому) усвоению знаний.

Итак, вот перевод. Прошу отнестись с пониманием (с) ;-). Все очепятки мои

Набрав что такое machine learning? в поисковой строке Google, можно открыть ящик Пандоры форумов, научных исследований и ложной информации и цель этой статьи состоит в том, чтобы упростить определение и понимание термина машинное усвоение благодаря прямой помощи со стороны группы экспертов-исследователей.

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

Эта статья будет разбита на следующие ниже разделы:

  • Что такое машинное усвоение?

  • Как мы пришли к нашему определению (посредством разных точек зрения экспертов-исследователей)

  • Базовые концепции машинного усвоения

  • Визуальные представления моделей машинного усвоения

  • Как мы обеспечиваем машины способностью усваивать знания

  • Обзор трудностей и пределов машинного усвоения

  • Краткое введение в глубокое усвоение знаний

  • Цитируемые работы

  • Интервью по данной теме

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

Что такое машинное усвоение?

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

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

Как мы пришли к нашему определению

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

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

2. Машинное усвоение - это наука о том, как обеспечивать компьютеры способностью действовать без явного на то программирования Стэнфорд

3. Машинное усвоение основывается на алгоритмах, которые могут усваивать знания из данных, не опираясь в этом на программирование на основе правил -McKinsey & Co.

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

5. Область машинного усвоения стремится ответить на вопрос о том, как строить компьютерные системы, которые совершенствуются автоматически вместе с опытом, и каковы фундаментальные законы, которые управляют всеми процессами усвоения знаний? Университет Карнеги Мелона

Мы разослали эти определения экспертам, которых мы опросили и/или включили в один из прошлых исследовательских консенсусных опросов, и попросили их ответить своим определением либо предоставить свое собственное. Наше вводное определение отражает разнообразные ответы. Ниже приведено несколько ответов:

Д-р Иошуа Бенжио, Монреальский университет:

Термин не должен определяться использованием отрицаний (отсюда, пункты 2 и 3 исключаются). Вот мое определение:

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

Д-р Данко Николич, CSC и Институт Макса Планка:

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

Д-р Роман Ямпольский, Университет Луисвилла:

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

Доктор Эмили Фокс, Вашингтонский университет:

Мое любимое определение - пункт 5.

Базовые концепции машинного усвоения

Существует много разных типов алгоритмов машинного усвоения знаний, сотни из которых публикуются каждый день, и они, как правило, группируются либо по стилю усвоения (т. е. контролируемое усвоение, неконтролируемое усвоение, полуконтролируемое усвоение), либо по сходству формы или функции (т. е. классификация, регрессия, дерево решений, кластеризация, глубокое усвоение и т. д.). Независимо от стиля усвоения или функции, все комбинации алгоритмов машинного усвоения знаний состоят из следующих ниже компонентов:

  • Представление (набор классификаторов или понятный компьютеру язык)

  • Оценивание (aka целевая функция/функция оценивания)

  • Оптимизация (метод поиска; нередко, например, классификатор с наивысшей оценкой; используются как готовые, так и конкретно-прикладные методы оптимизации)

Автор таблицы: д-р Педро Доминго, Вашингтонский университетАвтор таблицы: д-р Педро Доминго, Вашингтонский университет

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

Визуализации моделей машинного усвоения знаний

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

Модель на основе дерева решений:

Дерево решенийДерево решений

Модель на основе гауссовой смеси:

Гауссова смесьГауссова смесь

Нейронная сеть с отсевом

Как мы обеспечиваем машины способностью усваивать знания

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

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

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

Иногда это также происходит непреднамеренно. В качестве одного примера можно взять модельные ансамбли, или комбинации многочисленных алгоритмов усвоения знаний, служащих для повышения точности. Коллективы разработчиков, участвовавшие в конкурсе Приз Netflix 2009 года, обнаружили, что они получили свои наилучшие результаты после того, как совместили своих учеников с учениками других коллективов, что привело к быстрому рекомендательному алгоритму (подробнее о том, почему они не использовали этот ансамбль, читайте в блоге Netflix).

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

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

Обзор трудностей и пределов машинного усвоения

Машинное усвоение знаний не может получать что-то из ничего но оно умеет получать больше из меньшего Доктор Педро Доминго, Вашингтонский университет

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

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

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

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

Глубокое усвоение и новейшие разработки в нейронных сетях

Глубокое усвоение знаний предусматривает изучение и разработку машинных алгоритмов для усвоения хорошего представления данных в нескольких слоях абстракции (способах организации компьютерных систем). Недавнее публичное освещение глубокого усвоения со стороны DeepMind, Facebook и других учреждений высветила его как следующий рубеж машинного усвоения знаний.

Международная конференция по машинному усвоению (International Conference on Machine Learning, аббр. ICML) широко считается одной из самых важных в мире. В 2019 году она проводилась в Нью-Йорке и собрала исследователей со всего мира, которые работают над решением текущих проблем в области глубокого усвоения знаний:

  1. Неконтролируемое усвоение в малых наборах данных

  2. Усвоение на основе симуляций и переносимость в реальный мир

За последнее десятилетие системы глубокого усвоения добились больших успехов в таких областях, как обнаружение и распознавание объектов, преобразование текста в речь, информационный поиск и другие. В настоящее время исследования сосредоточены на разработке эффективного машинного усвоения знаний, т. е. систем глубокого усвоения, которые могут усваивать знания еще эффективнее, с той же результативностью за меньшее время и с меньшим объемом данных, в таких передовых областях, как персонализированное здравоохранение, стимулированное усвоение знаний роботом (robot reinforcement learning), анализ настроений и другие.

Ключевые тезисы по применению машинного усвоения знаний

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

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

  • Причина большинства случаев плохой работы алгоритмов связана с наличием проблем в тренировочных данных (например, недостаточность/искаженность данных; зашумленность данных; или недостаточное число признаков, которые описывают данные, для принятия решений

  • Из простоты не следует точность (согласно Доминго) между числом модельных параметров и склонностью к переподгонке нет заданной связи

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

  • Независимо от того, как мы называем данные - причинно-следственными или коррелятивными, - более важным моментом является предсказание последствий наших действий

  • Следует всегда откладывать порцию тренировочных данных в сторону для целей перекрестной валидации, если хотите, чтобы выбранный вами классификатор или алгоритм усвоения хорошо работал на свежих данных

Цитируемые работы

1 http://homes.cs.washington.edu/~pedrod/papers/cacm12.pd

2 http://videolectures.net/deeplearning2016_precup_machine_learning/

3 http://www.aaai.org/ojs/index.php/aimagazine/article/view/2367/2272

4 https://research.facebook.com/blog/facebook-researchers-focus-on-the-most-challenging-machine-learning-questions-at-icml-2016/

5 https://sites.google.com/site/dataefficientml/

6 http://www.cl.uni-heidelberg.de/courses/ws14/deepl/BengioETAL12.pdf

Интервью в Emerj по темам, связанным с машинным усвоением знаний

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

Выводы

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

Подробнее..

Стандарт C20 обзор новых возможностей C. Часть 1 Модули и краткая история C

29.04.2021 18:18:03 | Автор: admin


25 февраля автор курса Разработчик C++ в Яндекс.Практикуме Георгий Осипов рассказал о новом этапе языка C++ Стандарте C++20. В лекции сделан обзор всех основных нововведений Стандарта, рассказывается, как их применять уже сейчас и чем они могут быть полезны.

При подготовке вебинара стояла цель сделать обзор всех ключевых возможностей C++20. Поэтому вебинар получился насыщенным. Он растянулся на почти 2,5 часа. Для вашего удобства текст мы разбили на шесть частей:

  1. Модули и краткая история C++.
  2. Операция космический корабль.
  3. Концепты.
  4. Ranges.
  5. Корутины.
  6. Другие фичи ядра и стандартной библиотеки. Заключение.

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

Краткая история C++


В самом начале я задал слушателям вебинара вопрос: сколько всего существует стандартов C++?

Результаты голосования:

  • правильных ответов 58 (96.67%)
  • неправильных ответов 2 (3.33%)



Давайте посчитаем. Бьёрн Страуструп занялся разработкой C++ в восьмидесятых годах. К нему пришли люди из ISO [международная комиссия по стандартизации] и предложили стандартизировать язык. Так и появился C++98 первый Стандарт.

Прошло пять лет, и Стандарт исправили. Получился C++03. Это было не что-то революционное, а просто исправление ошибок. Кстати, иногда C++03 не считают отдельным Стандартом. Возможно, C++03 самый популярный Стандарт с точки зрения примеров в интернете и ответов на Stack Overflow, но назвать его современным C++ сейчас невозможно.

Всё изменил следующий Стандарт, который планировалось выпустить до 2010 года. Он носил кодовое название C++0x, которое потом сменилось на C++1x. Решить все проблемы и издать Стандарт смогли только в 2011 году, он получил название C++11. Заметно расширились возможности языка: там появились auto, move-семантика, variadic templates. Когда я учил этот Стандарт, у меня возникло ощущение, что освоить C++11 равносильно изучению нового C++.

Прошло три года. Вышел C++14. Он не стал таким революционным и в основном содержал фиксы ошибок, неизбежных при принятии такого огромного набора документов, как C++11. Но и в 2014 году добавилось новое.

Ещё через три года C++17 добавил больше интересных вещей: дополнительные возможности стандартной библиотеки, распаковку при присваивании и прочее.

Логично ожидать, что за большим Стандартом последует Стандарт с исправлениями ошибок. Но что-то пошло не так. C++20 это практически новый язык. По количеству нововведений он сравним с C++11, а может быть, обгоняет его.



Мы рассмотрим несколько ключевых возможностей C++20. Их список есть в анонсе: это модули, концепты, ranges, корутины. Также будет дан краткий обзор всего, что не вошло в этот список: другие фичи ядра и стандартной библиотеки. Пойдём по порядку.

Модули




Мотивация


Код на C++ хранится в .cpp, .cxx, .cc файлах. На самом деле этот код программа не на C++, а на языке препроцессора C++. Это другой язык, который не понимает синтаксис C++. И наоборот, C++ не понимает синтаксис препроцессора. Формально он входит в Стандарт, поэтому препроцессор можно относить к C++. Но фактически это два разных языка.

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

До C++20 вместо модулей использовали хедеры отдельные текстовые файлы .h. При подключении хедера программой на C++ он просто копируется в место включения. В связи с этим возникает много проблем.

  • Дублирование. При добавлении определения функции в .cpp-файл, нужно добавить объявление в .h-файл. А дублирование порождает ошибки.
  • Неочевидный побочный эффект включения заголовочных файлов. В зависимости от порядка расположения два скопированных фрагмента могут влиять друг на друга.
  • Нарушение one definition rule
    Правило одного определения. В программе не должно быть конфликтующих определений одной и той же сущностей. Наличие нескольких определений может влечь неопределённое поведение
    Функция или класс могут включаться в разные файлы .cpp, разные единицы трансляции. Если вдруг они включились по-разному например, в этих единицах трансляции определены разные макросы, нарушится one definition rule. Это серьёзная ошибка.
  • Неконсистентность включений. То, что включится из хедера, зависит от макросов, которые определены в момент включения хедера.
  • Медленная компиляция. Когда один и тот же хедер целиком включается в разные единицы трансляции, компилятор вынужден его компилировать каждый раз. Кстати, это же касается стандартных библиотек. Например, iostream это огромный файл, и компилятор вынужден компилировать его со всеми зависимыми единицами трансляции.
  • Мы не можем контролировать, что нужно экспортировать, а что нет. При включении хедера единица трансляции получит всё, что в нём написано, даже если это не предназначено для включения.

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

В итоге использование хедеров:

  • небезопасно;
  • повышает время компиляции;
  • некрасиво: компилятор никак не обрабатывает процедуру включения, а просто вставляет один текст в другой.

У хедеров есть плюсы. Перечислять их я, конечно же, не буду.

Что у других


Посмотрим на ситуацию в других языках ведь модули есть везде. Для примера возьмём Python. Мне нравится, как модули реализованы в нём. Есть возможность импортировать модуль целиком или ограничиться определёнными именами. При импорте имена можно переназвать. На слайде вы видите небольшой пример.



Или рассмотрим Fortran. Выбор может показаться неожиданным, но почему бы не рассмотреть его, раз такой язык существует, и в нём есть модули. Сам Fortran появился в 1957 году, а модули ввели в 1991-м. Соответственно, схему придумали когда-то между этими двумя датами. Пример на слайде просто иллюстрация, к модулям она не относится.



В Fortran единицу трансляции можно скомпилировать только в том случае, если все зависимости уже скомпилированы. Из-за этого появилось правило run make until it succeeds, то есть нужно продолжать запускать make, пока наконец не скомпилируется. В первый раз скомпилируются модули, у которых нет зависимостей, во второй раз модули, которые зависели от первых. В какой-то момент вся программа соберётся. Если повезёт, даже раньше, чем вы ожидаете.

Как вы думаете, по какому пути пошёл C++?



Конечно же, по пути Фортрана! Хотя за три десятка лет в Фортране как-то научились обходить проблемы модулей, фортрановские решения для C++ не годятся ситуация сложнее.

Но не всё так плохо.

Пример


Рассмотрим пример из трёх файлов. Заметьте, что два из них имеют расширение .cppm такое расширение для модулей принято в компиляторе Clang. Третий файл обычный .cpp, который импортирует модули.



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

При компиляции примера нужно вначале собрать модуль foo2.cppm, потому что он ни от чего не зависит. Затем нужно собрать foo.cppm и только потом bar.cpp.

Почему сделали именно так? Комитет по стандартизации пошёл от решения проблемы наличия двух файлов. Хотелось иметь не два файла хедер и .cpp, а один. Из этого файла предлагается автоматически получать аналог заголовочного файла, который содержал бы всё необходимое для тех, кто его импортирует.

Поэтому компилировать проект с модулями нужно два раза. Появляется новая операция предкомпиляция. На слайде я привёл команды для сборки этой программы компилятором Clang.



Для начала нужно предкомпилировать оба файла .cppm. Создастся файл с расширением .pcm бинарный аналог файла .h. То есть h-файл теперь не нужно создавать вручную. Затем собирается вся программа. В данном случае это bar.cpp, который зависит от двух модулей.

В Visual Studio модули реализованы из коробки. Вы добавляете в проект module unit с расширением .ixx, и VS всё соберёт за вас.

Эта концепция полностью ломает некоторые из существующих систем сборки C++ кода. Хотя всё налаживается. К примеру, в CMake добавили экспериментальную поддержку модулей. Такие системы, как Build2, b2, cxx_modules_builder, xmake, Meson, autotools, Tup, Scons, уже поддерживают модули.

Теория


Рассмотрим, какие проблемы модули решают, а какие не решают. Зададим вопросы.

  • Можем ли мы импортировать выбранные имена?
  • Получится ли переназвать имена при импорте, как в Python?
  • Структурируют ли модули имена?

Ответ на эти три вопроса: нет. Импортируется всё, что экспортирует модуль, причём под теми же именами. Модули вообще не структурируют имена в C++. Для структурирования, как и раньше, используются пространства имён. Модули могут экспортировать их.

Следующий блок вопросов.

  • Импортируются только нужные имена?
  • Ускоряют ли модули процесс сборки?
  • Модули не влияют друга на друга?
  • Не пишем больше отдельно .cpp и .h?
  • Не можем испортить код других модулей макросами при импорте?

Ответы на них да. Это те проблемы, которые решает новый Стандарт.

Последний вопрос.

  • В Python при импорте можно выполнять произвольный код. Есть ли в C++ такое?

В C++ импорт происходит во время compile-time, а не в runtime. Поэтому вопрос не имеет смысла.

Модули нарушают несколько устоявшихся принципов C++:

  1. Принцип независимости сборки. До этого программа на C++ состояла из разных единиц трансляции файлов .cpp. Каждый из них можно было компилировать отдельно: сегодня один, завтра другой, через неделю третий, а потом уже слинковать всё вместе. Теперь порядок не произвольный. Файл нельзя собрать, пока не предкомпилированы модули, от которых он зависит. Поэтому собрать модуль не получится, если в каком-то зависимом модуле ошибка. Процесс сборки сильно усложняется.
  2. Принцип гомогенности кода. Хотя #include обычно пишут в начале, это договорённость, а не правило. Его можно писать в любом месте программы. И так со всем, что есть в C++: никакой глобальной структуры у кода до C++20 не было. Синтаксические конструкции могли идти в любом порядке. Новым Стандартом вводится преамбула. И только в ней могут располагаться импорты модулей. Как только преамбула закончилась, писать import стало нельзя. У файла кода появляется структура. Кроме того, перед преамбулой возможна предпреамбула так называемый Global module fragment. В нём могут располагаться только директивы препроцессора. Но они допускают #include, а значит, по факту всё что угодно. Подробно разбирать Global module fragment не будем.

Я считаю появление структуры хорошим шагом, но это нарушение давно существовавших принципов C++.

Модули добавляют новые понятия. Например, новые типы единиц трансляции они называются module unit и header unit. Появился тип компоновки module linkage.

Module unit бывают двух типов:

  • Module interface unit. Начинается с export module.
  • Module implementation unit. Начинается с module.

Разница у них в том, что module interface unit это интерфейс, предназначенный для тех, кто этот модуль будет импортировать. К нему может прилагаться любое количество module implementation units, в которые по желанию выносятся реализации функций и методов из этого модуля. Главное правило: для каждого модуля ровно один module interface unit и сколько угодно module implementation unit.

В большинстве случаев module implementation unit вообще не понадобится. Он предназначен для больших модулей, код которых сам по себе требуется структурировать. Поэтому чаще всего один модуль один module interface unit.

Посмотрим на допустимый формат импорта и экспорта из модулей.

import M;import "my_header.h";import <version>;

Модуль и любые cpp-файлы могут импортировать другие модули и, внезапно, заголовочные файлы. Последнее, к сожалению, мне пока не удалось протестировать у компиляторов явно какие-то проблемы.

В теории, чтобы импортировать .h-файл, его тоже нужно предкомпилировать. При этом заголовок, который раньше был лишь придатком cpp-файла, рассматривается как самостоятельная единица трансляции, а вернее, header unit. Компилятор C++ вынет из него все имена и сделает подобие предкомпилированного модуля. Модуль в старом стиле, почему нет?

Интересно, что при этом импортируются макросы то, от чего нас пытается избавить новый Стандарт. По легенде, когда комитет по стандартизации хотел полностью вычеркнуть импорт макросов, к нему обратились представители Microsoft. Они заявили, что никак не могут обойтись в Windows.h без макросов min, max и некоторых других. Меня сейчас поняли те, кто программирует на C++ под Windows.

В отличие от #include, при импорте нужна точка с запятой.

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

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

Посмотрим на примерах. Из модулей экспортируются:

  • декларации и определения, создающие имя (типы, using-декларации, функции, глобальные переменные, классы, enum). В том числе шаблонные.

export module M;export template<class R>struct Point {    R x, y;};export int f();int f() { return 42; }export int global_variable = 42;

  • Целые namespaceы или декларации внутри namespace'ов.

export namespace {    int prime_number = 13;    class CppCompiler {};}namespace A { // exported   export int f(); // exported   int g(); // not exported}

Тут можно найти ещё одно применение безымянным namespace.

  • Другие модули

export import MyModule;

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

  • Любые имена через using.

struct F {};export using ::F;

Таким образом, имена тоже экспортируются: для этого пишите :: перед именем, потому что using требует указания пространства имён.

  • Имена под другим именем.

export using G = ::F;

Модули поддерживают структурирование своих имён, но на этом останавливаться не будем. Там всё непросто и запутанно. Структурирование это примерно как подпапки в файловой системе. Пакеты отделяются символом :. Ниже пример со структурированием имён модулей. Это слегка отредактированный пример из Стандарта.

// TU 1export module A;export import :Foo;export int baz();// TU 2export module A:Foo;import :Internals;export int foo() { return 2 * (bar() + 1); }// TU 3export module A:Internals;int bar();// TU 4module A; int baz() { return 30; }int bar() { return baz() - 10; }

Статус




В Visual Studio у модулей частичная поддержка. Очень здорово, что в VS стандартная библиотека уже реализована на модулях, то есть вы можете написать import std.core;. Импорт h-файлов в VS пока не работает.

В GCC поддержки модулей нет в trunk, но есть в ветке. Эту ветку планируют влить в GCC 11.

В Clang модули присутствуют давно. Вообще даже техническая спецификация модулей, принятая в C++20, далеко не первая. Их давно обсуждали и даже планировали включить в Стандарт C++17, но не успели. Clang поддерживает обе спецификации: новую и старую, но всё равно не полностью.

Насколько мне известно, ни один из компиляторов не поддерживает модули полностью. Я считаю, что время модулей пока не пришло. Модули сырая фича, которая не везде реализована хорошо, хотя все основные компиляторы уже о ней отчитались. Будем надеяться, что вскоре мы сможем полноценно пользоваться модулями.

Заключение


Во время трансляции мы провели голосование, крутая это фича или нет. Результаты опроса:

  • Суперфича 16 (23.53%)
  • Так себе фича 6 (8.82%)
  • Пока неясно 46 (67.65%)

Расскажу о своём мнении по этому вопросу. Я считаю, что модули нужны обязательно, потому что так, как было 40 лет назад в C, никуда не годится. Во всех современных языках есть модули, почему в нашем современном языке их нет? Конечно, модули решают далеко не все проблемы: проблемы структурирования имён и распространения пакетов остаются нерешёнными. Но всё-таки они ускоряют сборку, структурируют зависимости, избавляют от дублирования и нарушения ODR. Поэтому вещь очень полезная.

Главный минус: существенно усложняется процесс сборки. С их активным применением я бы пока подождал.

Опрос


Читателям Хабра, как и слушателям вебинара, дадим возможность оценить нововведения.
Подробнее..

Чему равно выражение -33u3 на С? Не угадаете. Ответ -4. Приглашаю на небольшое расследование

04.05.2021 18:23:50 | Автор: admin

Вот пример для проверки:

#include <iostream>int main(){    std::cout << "-3/3u*3 = " << int(-3/3u*3) << "\n";}

Посмотреть результат можно тут.

Или попробуйте поиграться с этим примером здесь или здесь.

Вообще-то мне не удалось найти хоть какой-то компилятор С++, который бы выдавал результат отличный от -4. Даже старый GCC-4.1.2, clang-3.0.0 или Borland C 1992 года. Так же заметил, что результат одинаковый и для константы, вычисляемой в момент компиляции и для времени выполнения.

Предлагаю внимательно рассмотреть результат выражения -3/3u*3.

Если убрать приведение к типу intв примере выше, то получим 4294967292 или 0xFFFFFFFС(-4). Получается, что компилятор на самом деле считает результат беззнаковым и равным 4294967292. До этого момента я был свято уверен, что если в выражении используется знаковый тип, то и результат будет знаковым. Логично же это.

Если посмотреть откуда берется -4 вместо -3, посмотрим внимательней на ассемблерный код примера, например здесь.

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

int main(){    volatile unsigned B = 3;    int A = -3/B*3;}

Для x86-64 clang 12.0.0 видим, что используется беззнаковое деление, хотя числитель откровенно отрицательное -3:

        mov     dword ptr [rbp - 4], 3    // B = 3        mov     ecx, dword ptr [rbp - 4]        mov     eax, 4294967293        xor     edx, edx        div     ecx                       // беззнаковое деление !!        imul    eax, eax, 3               // знаковое умножение        mov     dword ptr [rbp - 8], eax

Для x64 msvc v19.28 тот же подход к делению:

        mov     DWORD PTR B$[rsp], 3      // B = 3        mov     eax, DWORD PTR B$[rsp]        mov     DWORD PTR tv64[rsp], eax        xor     edx, edx        mov     eax, -3                             ; fffffffdH        mov     ecx, DWORD PTR tv64[rsp]        div     ecx        imul    eax, eax, 3        mov     DWORD PTR A$[rsp], eax

Получается, что для деления беззнакового числа на знаковое используется БЕЗЗНАКОВАЯ операция деления процессора div. Кстати, следующая команда процессора, это правильное знаковое умножение imul. Ну явный баг компилятора. Банальная логика же подсказывает, что знаковый тип выиграет в приведении типа результата выражения если оба знаковый и беззнаковый типы используются в выражении. И для знакового деления требуется знаковая команда деления процессора idiv, чтоб получить правильный результат со знаком.

Проблема еще и в том, что число 4294967293 не делится на 3 без остатка:4294967293 = 1431655764 * 3 + 1и при умножении 1431655764 обратно на 3, получаем 4294967292 или -4. Так что прикинуться веником и считать, что 4294967293 это то же -3, только вид сбоку, для операции деления не прокатит.

Двоично-дополнительное придставление отрицательных чисел.

Благодаря представлению чисел в двоично-дополнительном виде, операции сложения или вычитания над знаковыми и без-знаковыми числами выполняются одной и той же командой процессора (add для сложения и sub для вычитания). Процессор складывает (или вычитает) только знаковое со знаковым или только без-знаковое с без-знаковым. И для обоих этих операций используется одна команда add (или sub) и побитово результат будет одинаковый (если бы кто-то решил сделать раздельные операции сложения для знаковых и без-знаковых типов). Различие только во флагах процессора. Так что считать знаковое без-знаковым и складывать их оба как без-знаковых корректно и результат будет побитово правильным в обоих случаях. Но для деления и умножения этот подход в корне неправильный. Процессор внутри использует только без-знаковые числа для деления и умножения и результат приводит обратно в знаковое с правильным признаком знака. И для этого процессор использует разные команды для знакового (idiv) и без-знакового деления (div) и так же и для умножения (imul и соответственно mul).

Я когда обнаружил, что используется без-знаковое деление, решил, что это бага компилятора. Протестировал много компиляторов: msvc, gcc, clang. Все показали такой же результат, даже древние трудяги. Но мне довольно быстро подсказали, что это поведение описано и закреплено в самом стандарте.

Действительно, стандарт говорит об этом прямо:

Otherwise, if the unsigned operand's conversion rank is greater or equal to the conversion rank of" "the signed operand, the signed operand is converted to the unsigned operand's type.

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

Вот где оказывается собака зарыта: "the signed operand is converted to the unsigned operand's type"!! Ну почему, почему, Карл!! Логичнее наоборот: "the unsigned operand is converted to the signed operand's type", разумеется при соблюдении ранга преобразования. Ну вот как -3 представить без-знаковым числом?? Наоборот кстати можно.

Интересная получается сегрегация по знаковому признаку!

Заметил, что это правило почему-то работает только для операции деления, а операция умножения вычисляется правильно.

Проверим на ассемблере здесь этот пример:

int main(){    volatile unsigned B = 3;    int C = -3*B;}
Вот ассемблерный код:

mov dword ptr [rbp - 4], 3 mov eax, dword ptr [rbp - 4] imul eax, eax, 4294967293 mov dword ptr [rbp - 8], eax

Стандарт ничего не говорит о неприменимости этого правила для операции умножения. И деление и умножение должны быть БЕЗЗНАКОВМИ.

Я подумал, что что-то в стандарте сломалось и надо срочно это исправить. Написал письмо напрямую в поддержку Стандарта со всеми моими выкладками и предложением поправить это странное правило стандарта пока еще не поздно.

Ага! Наивный!

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

Хоть это исследование и было больше года назад, я до сих пор под впечатлением от многих вещей в этой истории:

  • Как я не натыкался на это раньше? Не один десяток лет интенсивно кодирую на С и С++ с погружением в ассемблер, но только сейчас споткнулся на неё. Хотя может и натыкался ранее, но не мог поверить что причина именно в этом.

  • Ассемблер я выучил раньше С и поэтому всегда считал С удобной заменой Ассемблера. Но правила работы процессоров неизменны и даже языки высокого уровня им следуют.

Интересно, что это правило всё же не работает и для операций с указателями. С ними нет такого поведения. Видать понимают разработчики компиляторов, что иначе рухнет очень многое. Посмотрите этот пример здесь:

int main(){    const unsigned a[] = {3,4,5,6,7};    unsigned p = (&a[0] - &a[3])/3u*3;    // -3    unsigned b = -3/3u*3;   // -4}

Хоть я и понимаю, что могу ошибаться в логике работы этого мира, но задумайтесь, в следующий раз садясь в современный, нашпигованный вычислительной логикой самолёт (или автомобиль), а не сработает ли вдруг не оттестированный кусок кода в какой-то редкой нештатной ситуации, и не выдаст ли он -4 вместо элементарных -3, и не постигнет ли его участь подобная Boeing 737 MAX?

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

Ошибка в команде просессора FDIV у Интела

Помните, в начале 2000-х была выявлена ошибка с вычислением в команде FDIV у Интела. Там было различие в 5 знаке после запятой в какой-то операции деления. Какой был шум тогда!!
Но исправили оперативно и быстро. В компиляторы добавили условный флаг для обхода этой команды. Интел срочно исправил логику в кристалле и выпустил новые чипы.

И это всего лишь 5-й знак после запятой! Многие его даже и не заметили, подумаешь, мелочь какая! А тут -4 вместо -3 и считаем знаковое без-знаковым и вместо -3 имеем еще и 4294967292! И тишина в ответ! И в этой тишине тихо падают Боинги.

Предвижу возражение, что есть рекомендация использовать преимущественно без-знаковый тип. Понимаю, с таким правилом Стандарта по другому никак. Но как -4 в беззнаковое перевести, и чтоб всё остальное работало? И почему на других языках и всех процессорах не надо этими танцами с бубном заниматься, а в С++ надо? И что делать с константными выражениями, вычисляемыми компилятором? Вместо элегантных выражений, в которых мы уверены, надо записывать их с оглядкой, чтоб у компилятора небыло изжоги!

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

Как хорошую подсказку познавательно добавить предупреждение в компилятор когда он применяет это правило из Стандарта:"Signed value is intentionally converted to unsigned value. Sorry for crashing one more airplane. Have a nice flight!" Вот удивимся тогда, как мало мы тестируем и как много нам открытий чудных приносит компилятор друг.

Можно еще исправить Стандарт, ограничив правило только операциями сложения и вычитания. Как компромис. Но это крайне маловероятно в этой Вселенной. Да и Боингов еще много летает.

Представьте студента (С) на экзамене у преподавателя по информатике (П) в ВУЗе.

- П: Хорошо, последний вопрос на 5. Можно ли привести знаковое число к беззнаковому типу?
- С: Хе, можно. НУЖНО! Обязательно НУЖНО! Ставте 5, я пойду.
- П: Как НУЖНО?? О_О. Подумайте. Как можно представить, например, -4 беззнаковым числом? - С: Чего тут думать! Стандарт С++ сказал, что НУЖНО, значит НУЖНО и точка. А то что -4 станет беззнаковым очень большим числом - это уже ни печалька Стандарта, ни моя. - П: Подумайте еще раз. Вы на экзамене по информатике и вас спрашивают о базовых вещах, которые общие для всех языков программирования и процессоров, а не только для С++. - С: Чего вы пристали к мне со своими языками и процессорами. У меня в билете вопрос про С++, вот я про С++ и отвечаю. А вы про какой то там Ассемблер, базовые вещи, языки программирования! Стандарт С++ сказал, компилятор сделал, я ответил! У вас есть вопросы к Стандарту про базовые вещи, вот ему их и задавайте, а я ответил правильно! - П: Да уж. Подстава конкретная.

Подробнее..

Стандарт C20 обзор новых возможностей C. Часть 2 Операция Космический Корабль

05.05.2021 12:08:12 | Автор: admin


25 февраля автор курса Разработчик C++ в Яндекс.Практикуме Георгий Осипов рассказал о новом этапе языка C++ Стандарте C++20. В лекции сделан обзор всех основных нововведений Стандарта, рассказывается, как их применять уже сейчас и чем они могут быть полезны.

При подготовке вебинара стояла цель сделать обзор всех ключевых возможностей C++20. Поэтому вебинар получился насыщенным. Он растянулся почти на 2,5 часа. Для вашего удобства мы разбили текст на шесть частей:

  1. Модули и краткая история C++.
  2. Операция космический корабль.
  3. Концепты.
  4. Ranges.
  5. Корутины.
  6. Другие фичи ядра и стандартной библиотеки. Заключение.

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

Это вторая часть, рассказывающая об операции космический корабль в современном C++.

Операция космический корабль


В C++ теперь свой космос!



Мотивация


В C++ шесть операций сравнения:

  1. меньше,
  2. больше,
  3. меньше или равно,
  4. больше или равно,
  5. равно,
  6. не равно.

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

Предположим, вы определили структуру, содержащую одно число:

struct X {    int a;};

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

bool operator== (X l, X r) { return l.a == r.a; }bool operator!= (X l, X r) { return l.a != r.a; }bool operator>= (X l, X r) { return l.a >= r.a; }bool operator<= (X l, X r) { return l.a <= r.a; }bool operator< (X l, X r) { return l.a < r.a; }bool operator> (X l, X r) { return l.a > r.a; }

А теперь представьте, что мы хотим сравнивать элементы этой структуры не только между собой, но также с числами int. Количество операций возрастает с шести до 18:

bool operator== (X l, int r) { return l.a == r; }bool operator!= (X l, int r) { return l.a != r; }bool operator>= (X l, int r) { return l.a >= r; }bool operator<= (X l, int r) { return l.a <= r; }bool operator< (X l, int r) { return l.a < r; }bool operator> (X l, int r) { return l.a > r; }bool operator== (int l, X r) { return l == r.a; }bool operator!= (int l, X r) { return l != r.a; }bool operator>= (int l, X r) { return l >= r.a; }bool operator<= (int l, X r) { return l <= r.a; }bool operator< (int l, X r) { return l < r.a; }bool operator> (int l, X r) { return l > r.a; }

Что делать? Можно позвать штурмовиков. Их много, и они быстро напишут 18 операций.



Или воспользоваться космическим кораблём. Эту новую операцию в C++ называют космический корабль, потому что она на него похожа: <=>. Более формальное название трёхстороннее сравнение фигурирует в документах Стандарта.

Пример


В структуру X я добавил всего одну строчку, определяющую операцию <=>. Заметьте, что я даже не написал, что именно она делает:

#include <iostream>struct X {    auto operator<=>(const X&) const = default; // <-- !    int a;};

И C++ всё сделал за меня. Это сработает и в более сложных случаях, например, когда у X несколько полей и базовых классов. При этом всё, что есть в X, должно поддерживать сравнение. После того, как я написал эту магическую строчку, я могу сравнивать объекты X любым способом:

int main() {    X x1{1}, x42{42};    std::cout << (x1 < x42 ? "x1 < x42" : "not x1 < x42") << std::endl;    std::cout << (x1 > x42 ? "x1 > x42" : "not x1 > x42") << std::endl;    std::cout << (x1 <= x42 ? "x1 <= x42" : "not x1 <= x42") << std::endl;    std::cout << (x1 >= x42 ? "x1 >= x42" : "not x1 >= x42") << std::endl;    std::cout << (x1 == x42 ? "x1 == x42" : "not x1 == x42") << std::endl;    std::cout << (x1 != x42 ? "x1 != x42" : "not x1 != x42") << std::endl;}

Получилась корректная программа. Её можно собрать и запустить. Текстовый вывод выглядит так:

x1 < x42not x1 > x42x1 <= x42not x1 >= x42not x1 == x42x1 != x42

Операция космического корабля сработает и для сравнения элемента структуры X с числом. Но придётся написать реализацию. На этот раз C++ не сможет придумать её за вас. В реализации воспользуемся встроенной операцией <=> для чисел:

#include <iostream>struct X {    auto operator<=>(const X&) const = default;     auto operator<=>(int r) const {   // <-- !        return this->a <=> r;    }    int a;};

Правда, возникает проблема. C++ создаст не все операции. Если вы определили эту операцию не через default, а написали сами, проверка на равенство и неравенство не будет добавлена. Кто знает причины пишите в комменты.

int main() {    X x1{1}, x42{42};    std::cout << (x1 < 42 ? "x1 < 42" : "not x1 < 42") << std::endl;    std::cout << (x1 > 42 ? "x1 > 42" : "not x1 > 42") << std::endl;    std::cout << (x1 <= 42 ? "x1 <= 42" : "not x1 <= 42") << std::endl;    std::cout << (x1 >= 42 ? "x1 >= 42" : "not x1 >= 42") << std::endl;    std::cout << (x1 == 42 ? "x1 == 42" : "not x1 == 42") << std::endl; // <--- ошибка    std::cout << (x1 != 42 ? "x1 != 42" : "not x1 != 42") << std::endl; // <--- ошибка}

Впрочем, никто не запрещает определить эту операцию самостоятельно. Ещё одно нововведение C++20: можно добавить проверку только на равенство, а неравенство добавится автоматически:

#include <iostream>struct X {    auto operator<=>(const X&) const = default;    bool operator==(const X&) const = default;    auto operator<=>(int r) const {        return this->a <=> r;    }    bool operator==(int r) const { // <-- !        return operator<=>(r) == 0;    }    int a;};int main() {    X x1{1}, x42{42};    std::cout << (x1 < 42 ? "x1 < 42" : "not x1 < 42") << std::endl;    std::cout << (x1 > 42 ? "x1 > 42" : "not x1 > 42") << std::endl;    std::cout << (x1 <= 42 ? "x1 <= 42" : "not x1 <= 42") << std::endl;    std::cout << (x1 >= 42 ? "x1 >= 42" : "not x1 >= 42") << std::endl;    std::cout << (x1 == 42 ? "x1 == 42" : "not x1 == 42") << std::endl;    std::cout << (x1 != 42 ? "x1 != 42" : "not x1 != 42") << std::endl;}

Хоть 2 операции и пришлось определить, но это гораздо лучше, чем 18.

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

#include <iostream>struct X {    auto operator<=>(const X&) const = default;    bool operator==(const X&) const = default;    auto operator<=>(int r) const {        return this->a <=> r;    }    bool operator==(int r) const { // <-- !        return operator<=>(r) == 0;    }    int a;};int main() {    X x1{1}, x42{42};    std::cout << (1 < x42 ? "1 < x42" : "not 1 < x42") << std::endl;    std::cout << (1 > x42 ? "1 > x42" : "not 1 > x42") << std::endl;    std::cout << (1 <= x42 ? "1 <= x42" : "not 1 <= x42") << std::endl;    std::cout << (1 >= x42 ? "1 >= x42" : "not 1 >= x42") << std::endl;    std::cout << (1 == x42 ? "1 == x42" : "not 1 == x42") << std::endl;    std::cout << (1 != x42 ? "1 != x42" : "not 1 != x42") << std::endl;}

Теория


На этом рассказ про космический корабль можно было бы завершить, но, оказывается, не всё так просто. Есть ещё несколько нюансов.

Первый: всё, что я сказал это неправда. Никаких операций сравнения на самом деле не добавилось. Если вы попробуете явно вызвать операцию меньше, компилятор скажет: Ошибка. Такой операции нет. Несмотря на то, что сравнение работает, получить адрес операции меньше не получится:

#include <iostream>struct X {    auto operator<=>(const X&) const = default;     int a;};int main() {    X x1{1}, x42{42};    std::cout << (x1.operator<(x42) ? "<" : "!<")    // <--- ошибка              << std::endl; }

Удивительно, как же компилятор выполняет операцию, которой нет. Всё благодаря тому, что поменялись правила поведения компилятора при вычислении операций сравнения. Когда вы пишете x1 < x2, компилятор, как и раньше, проверяет наличие операции <. Но теперь, если он её не нашёл, то обязательно посмотрит операцию космического корабля. В примере она находится, поэтому он её использует. При этом, если типы операндов разные, компилятор посмотрит сравнение в обе стороны: сначала в одну, потом в другую. Поэтому нет необходимости определять третий космический корабль для сравнения int и типа X достаточно определить только вариант, где X слева.

Если вам по какой-то причине вместо x < y нравится писать x.operator<(y), то определите операцию < явно. У меня для вас хорошие новости: реализацию можно не писать. default будет работать для обычных операций сравнения так же, как и для <=>. Напишите его, и C++ определит его за вас. Вообще, C++20 многое делает за вас.

#include <iostream>struct X {    auto operator<=>(const X&) const = default;     bool operator<(const X&) const = default; // <-- !    int a;};int main() {    X x1{1}, x42{42};    std::cout << (x1.operator<(x42) ? "<" : "!<")              << std::endl;}

Заметьте, что у operator< потребовалось указать явный тип возврата bool. А в <=> эту работу предоставляли компилятору, указывая auto. Оно означает, что тип я писать не хочу: компилятор умный, он поймёт сам, что нужно поставить вместо auto. Но какой-то тип там есть функция же должна что-то возвращать.

Оказывается, тут не всё так просто. Это не bool, как для простых операций сравнения. Здесь сразу три варианта. Эти варианты разные виды упорядочивания:

  • std::strong_ordering. Линейный порядок, равные элементы которого неразличимы. Примеры: int, char, string.
  • std::weak_ordering. Линейный порядок, равные могут быть различимы. Примеры: string, сравниваемый без учёта регистра; порядок на точках плоскости, определяемый удалённостью от центра.
  • std::partial_ordering. Частичный порядок. Примеры: float, double, порядок по включению на объектах set.

Математики хорошо знакомы с этими понятиями, тут даже нет никакого программирования. Для остальных расскажем. Линейный порядок такой, при котором любые два элемента можно сравнить между собой. Пример линейного порядка целые числа: какие бы два числа мы ни взяли, их можно сравнить между собой.

При частичном порядке элементы могут быть несравнимы. Числа с плавающей запятой float и double подпадают под понятие частичного порядка, потому что у них есть специальное значение NaN, не сравнимое ни с каким другим числом.

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

Статус




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

  • GCC. Хорошо поддерживается с версии 10, хотя и не до конца. Полную поддержку обещают только в GCC 11.
  • Clang. Полная поддержка в версии 10.
  • Visual Studio. Полная поддержка в VS 2019.

Заключение


Во время трансляции мы опросили аудиторию, нравится ли ей эта функция. Результаты опроса:

  • Суперфича 47 (87.04%)
  • Так себе фича 2 (3.70%)
  • Пока неясно 5 (9.26%)

Мы довольно подробно разобрали операцию космический корабль, однако всё равно часть её функций осталась непокрытой. Например, интересный вопрос: как компилятор обработает ситуацию, в которой определено несколько операций сравнения с разными типами.

Читателям Хабра, как и слушателям вебинара, дадим возможность оценить нововведения.
Подробнее..

Почему шифрование DNS не всегда эффективно обсуждаем экспертные мнения на этот счет

08.05.2021 18:17:24 | Автор: admin

Новые протоколы DNS-over-HTTPS и DNS-over-TLS стали настоящим яблоком раздора в ИТ-сообществе. Шифрование DNS-запросов внедряет во все большее число браузеров, но среди экспертов есть и те, кто критикует этот подход. Они считают, что новые протоколы не оказывают положительного влияния на степень защищенности и в лучшем случае бесполезны.

Разберем несколько наиболее популярных аргументов по этому вопросу.

Фотография: Markus Spiske. Источник: Unsplash.comФотография: Markus Spiske. Источник: Unsplash.com

Возможность мониторинга остается

Протоколы DoH и DoT шифруют запросы к DNS-серверу и ответы на них. В теории такой подход должен надежно скрывать имена хостов, к которым обращается пользователь, от интернет-провайдера и злоумышленников. Однако на практике с этим возникает ряд нюансов.

В этом году эксперты из аналитической компании SANS Institute опубликовали исследование, посвященное анализу DNS-трафика в корпоративных сетях. Они провели серию тестов и сделали вывод, что инструменты для логирования, проксирования и криптоанализа позволяют получить точное представление о содержимом зашифрованных DNS-запросов (стр. 21).

В то же время основатель PowerDNS Берт Хуберт (Bert Hubert) говорит, что DoH шифрует данные, которые можно без особого труда получить в открытом виде из других источников. Например, интернет-провайдеры могут определить сайты, которые посещает клиент через протокол OCSP (RFC 6960). Он служит для получения статуса отзыва цифрового сертификата X.509 (описывает процедуры распределения открытых ключей). Ответы OCSP содержат серийный номер TLS-сертификата на сайте, и по нему легко определить название ресурса.

Есть уязвимые места

Специалист по информационной безопасности и один из разработчиков открытого дистрибутива Whonix отмечает, что существуют и другие способы заполучить информацию о посещаемых сайтах. Один из вариантов анализ Server Name Indication (SNI). Это расширение протокола TLS, и через него клиенты сами сообщают имя хоста, к которому желают подключиться.

Информация транслируется в открытом виде, и при желании её можно перехватить. Справедливости ради стоит отметить, что уже есть инструменты, позволяющие шифровать SNI например, проект Encrypted Client Hello (ECH). Он скрывает метаданные, передающиеся во время рукопожатия, однако инструмент и его аналоги пока не получили широкого распространения.

Даже если шифровать DNS-запросы и использовать другие предосторожности, остается пусть и очевидный, но весомый момент, связанный с IP-адресом ресурса, к которому подключается клиент. По оценке специалистов регионального интернет-регистратора APNIC, его достаточно для точной идентификации более 95% сайтов. В оставшиеся 5% входят IP-адреса, связанные с несколькими ресурсами. Но и эту проблему при желании можно обойти.

Новые кибератаки

Еще в 2019 году специалисты по информационной безопасности из Netlabобнаружили вредонос Godlua. Программа злоупотребляет особенностями DNS-over-HTTPS для проведения DDoS-атак. С помощью протокола зловред маскирует обмен данными с управляющими серверами.

В итоге антивирусное ПО не может его обнаружить.

Фотография: Rico Reutimann. Источник: Unsplash.comФотография: Rico Reutimann. Источник: Unsplash.com

Эксперты опасались, что за Godlua последуют другие вредоносы, невидимые для систем пассивного антивирусного мониторинга. Так и получилось в конце 2020 года в Huntress Labs обнаружили новый вирус. С помощью DoH он получает IP-адреса хостов, входящих в состав вредоносной инфраструктуры. Остается надеяться, что в ближайшее время появятся инструменты, которые помогут выявлять вредоносную активность в зашифрованном трафике корпоративных сетей и предупреждать администраторов о потенциальных рисках.

Что дальше

Можно сделать вывод о том, что для повышения приватности необходимо использовать комплексный набор инструментов, в том числе и VPN. Одного лишь шифрования DNS недостаточно для полного сокрытия истории браузинга. Однако технологии DNS-over-HTTPS и DNS-over-TLS можно рассматривать как еще один важный шаг к безопасному интернету.


Что еще почитать по теме:


Подробнее..

Стандарт C20 обзор новых возможностей C. Часть 3 Концепты

12.05.2021 14:11:23 | Автор: admin


25 февраля автор курса Разработчик C++ в Яндекс.Практикуме Георгий Осипов рассказал о новом этапе языка C++ Стандарте C++20. В лекции сделан обзор всех основных нововведений Стандарта, рассказывается, как их применять уже сейчас и чем они могут быть полезны.

При подготовке вебинара стояла цель сделать обзор всех ключевых возможностей C++20. Поэтому вебинар получился насыщенным и растянулся на почти 2,5 часа. Для вашего удобства текст мы разбили на шесть частей:

  1. Модули и краткая история C++.
  2. Операция космический корабль.
  3. Концепты.
  4. Ranges.
  5. Корутины.
  6. Другие фичи ядра и стандартной библиотеки. Заключение.

Это третья часть, рассказывающая о концептах и ограничениях в современном C++.

Концепты




Мотивация


Обобщённое программирование ключевое преимущество C++. Я знаю не все языки, но ничего подобного и на таком уровне не видел.

Однако у обобщённого программирования в C++ есть огромный минус: возникающие ошибки это боль. Рассмотрим простую программу, которая сортирует вектор. Взгляните на код и скажите, где в нём ошибка:

#include <vector>#include <algorithm>struct X {    int a;};int main() {    std::vector<X> v = { {10}, {9}, {11} };    // сортируем вектор    std::sort(v.begin(), v.end());}

Я определил структуру X с одним полем int, наполнил вектор объектами этой структуры и пытаюсь его отсортировать.

Надеюсь, вы ознакомились с примером и нашли ошибку. Оглашу ответ: компилятор считает, что ошибка в стандартной библиотеке. Вывод диагностики занимает примерно 60 строк и указывает на ошибку где-то внутри вспомогательного файла xutility. Прочитать и понять диагностику практически невозможно, но программисты C++ делают это ведь пользоваться шаблонами всё равно нужно.



Компилятор показывает, что ошибка в стандартной библиотеке, но это не значит, что нужно сразу писать в Комитет по стандартизации. На самом деле ошибка всё равно в нашей программе. Просто компилятор недостаточно умный, чтобы это понять, и сталкивается с ошибкой, когда заходит в стандартную библиотеку. Распутывая эту диагностику, можно дойти до ошибки. Но это:

  • сложно,
  • не всегда возможно в принципе.

Сформулируем первую проблему обобщённого программирования на C++: ошибки при использовании шаблонов совершенно нечитаемые и диагностируются не там, где сделаны, а в шаблоне.

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

Задачу можно решить хаком SFINAE, написав две функции. Хак использует std::enable_if. Это специальный шаблон в стандартной библиотеке, который содержит ошибку в случае если условие не выполнено. При инстанцировании шаблона компилятор отбрасывает декларации с ошибкой:

#include <type_traits>template <class T>T Abs(T x) {    return x >= 0 ? x : -x;}// вариант для чисел с плавающей точкойtemplate<class T>std::enable_if_t<std::is_floating_point_v<T>, bool>AreClose(T a, T b) {    return Abs(a - b) < static_cast<T>(0.000001);}// вариант для других объектовtemplate<class T>std::enable_if_t<!std::is_floating_point_v<T>, bool> AreClose(T a, T b) {    return a == b;}

В C++17 такую программу можно упростить с помощью if constexpr, хотя это сработает не во всех случаях.

Или ещё пример: я хочу написать функцию Print, которая печатает что угодно. Если ей передали контейнер, она напечатает все элементы, если не контейнер напечатает то, что передали. Мне придётся определить её для всех контейнеров: vector, list, set и других. Это неудобно и неуниверсально.

template<class T>void Print(std::ostream& out, const std::vector<T>& v) {    for (const auto& elem : v) {        out << elem << std::endl;    }}// тут нужно определить функцию для map, set, list, // deque, arraytemplate<class T>void Print(std::ostream& out, const T& v) {    out << v;}

Здесь SFINAE уже не поможет. Вернее, поможет, если постараться, но постараться придётся немало, и код получится монструозный.

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

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

Что у других


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

class Eq a where(==) :: a -> a -> Bool(/=) :: a -> a -> Bool

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

template<typename T>concept Eq =    requires(T a, T b) {        { a == b } -> std::convertible_to<bool>;        { a != b } -> std::convertible_to<bool>;    };

Если вы ещё не знакомы с концептами, понять написанное будет трудно. Сейчас всё объясню.

В Haskell эти ограничения обязательны. Если не сказать, что будет операция ==, то использовать её не получится. В C++ ограничения нестрогие. Даже если не прописать в концепте операцию, ей всё равно можно пользоваться ведь раньше вообще не было никаких ограничений, а новые стандарты стремятся не нарушать совместимость с предыдущими.

Пример


Дополним код программы, в которой вы недавно искали ошибку:

#include <vector>#include <algorithm>#include <concepts>template<class T>concept IterToComparable =     requires(T a, T b) {        {*a < *b} -> std::convertible_to<bool>;    };    // обратите внимание на IterToComparable вместо слова classtemplate<IterToComparable InputIt>void SortDefaultComparator(InputIt begin, InputIt end) {    std::sort(begin, end);}struct X {    int a;};int main() {    std::vector<X> v = { {10}, {9}, {11} };    SortDefaultComparator(v.begin(), v.end());}

Здесь мы создали концепт IterToComparable. Он показывает, что тип T это итератор, причём указывающий на значения, которые можно сравнивать. Результат сравнения что-то конвертируемое к bool, к примеру сам bool. Подробное объяснение чуть позже, пока что можно не вникать в этот код.

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

Концепт использовали вместо слова class или typename в конструкции с template. Раньше было template<class InputIt>, а теперь слово class заменили на имя концепта. Значит, параметр InputIt должен удовлетворять ограничению.

Сейчас, когда мы попытаемся скомпилировать эту программу, ошибка всплывёт не в стандартной библиотеке, а как и должно быть в main. И ошибка понятна, поскольку содержит всю необходимую информацию:

  • Что случилось? Вызов функции с невыполненным ограничением.
  • Какое ограничение не удовлетворено? IterToComparable<InputIt>
  • Почему? Выражение ((* a) < (* b)) некорректно.


Вывод компилятора читаемый и занимает 16 строк вместо 60.

main.cpp: In function 'int main()':main.cpp:24:45: error: **use of function** 'void SortDefaultComparator(InputIt, InputIt) [with InputIt = __gnu_cxx::__normal_iterator<X*, std::vector<X> >]' **with unsatisfied constraints**   24 |     SortDefaultComparator(v.begin(), v.end());      |                                             ^main.cpp:12:6: note: declared here   12 | void SortDefaultComparator(InputIt begin, InputIt end) {      |      ^~~~~~~~~~~~~~~~~~~~~main.cpp:12:6: note: constraints not satisfiedmain.cpp: In instantiation of 'void SortDefaultComparator(InputIt, InputIt) [with InputIt = __gnu_cxx::__normal_iterator<X*, std::vector<X> >]':main.cpp:24:45:   required from heremain.cpp:6:9:   **required for the satisfaction of 'IterToComparable<InputIt>'** [with InputIt = __gnu_cxx::__normal_iterator<X*, std::vector<X, std::allocator<X> > >]main.cpp:7:5:   in requirements with 'T a', 'T b' [with T = __gnu_cxx::__normal_iterator<X*, std::vector<X, std::allocator<X> > >]main.cpp:8:13: note: the required **expression '((* a) < (* b))' is invalid**, because    8 |         {*a < *b} -> std::convertible_to<bool>;      |          ~~~^~~~main.cpp:8:13: error: no match for 'operator<' (operand types are 'X' and 'X')

Добавим недостающую операцию сравнения в структуру, и программа скомпилируется без ошибок концепт удовлетворён:

struct X {    auto operator<=>(const X&) const = default;    int a;};

Точно так же можно улучшить второй пример, с enable_if. Этот шаблон больше не нужен. Вместо него используем стандартный концепт is_floating_point_v<T>. Получим две функции: одну для чисел с плавающей точкой, другую для прочих объектов:

#include <type_traits>template <class T>T Abs(T x) {    return x >= 0 ? x : -x;}// вариант для чисел с плавающей точкойtemplate<class T>requires(std::is_floating_point_v<T>)bool AreClose(T a, T b) {    return Abs(a - b) < static_cast<T>(0.000001);}// вариант для других объектовtemplate<class T>bool AreClose(T a, T b) {    return a == b;}

Модифицируем и функцию печати. Если вызов a.begin() и a.end() допустим, будем считать a контейнером.

#include <iostream>#include <vector>template<class T>concept HasBeginEnd =     requires(T a) {        a.begin();        a.end();    };template<HasBeginEnd T>void Print(std::ostream& out, const T& v) {    for (const auto& elem : v) {        out << elem << std::endl;    }}template<class T>void Print(std::ostream& out, const T& v) {    out << v;}

Опять же, это неидеальный пример, поскольку контейнер не просто что-то с begin и end, к нему предъявляется ещё масса требований. Но уже неплохо.

Лучше всего использовать готовый концепт, как is_floating_point_v из предыдущего примера. Для аналога контейнеров в стандартной библиотеке тоже есть концепт std::ranges::input_range. Но это уже совсем другая история.

Теория


Пришло время понять, что такое концепт. Ничего сложного тут на самом деле нет:

Концепт это имя для ограничения.

Мы свели его к другому понятию, определение которого уже содержательно, но может показаться странным:

Ограничение это шаблонное булево выражение.

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

Самое простое ограничение это true. Ему удовлетворяет любой тип.

template<class T> concept C1 = true;

Для ограничений доступны булевы операции и комбинации других ограничений:

template <class T>concept Integral = std::is_integral<T>::value;template <class T>concept SignedIntegral = Integral<T> &&                         std::is_signed<T>::value;template <class T>concept UnsignedIntegral = Integral<T> &&                           !SignedIntegral<T>;

В ограничениях можно использовать выражения и даже вызывать функции. Но функции должны быть constexpr они вычисляются на этапе компиляции:

template<typename T>constexpr bool get_value() { return T::value; } template<typename T>    requires (sizeof(T) > 1 && get_value<T>())void f(T); // #1 void f(int); // #2 void g() {    f('A'); // вызывает #2.}

И список возможностей этим не исчерпывается.

Для ограничений есть отличная возможность: проверка корректности выражения того, что оно компилируется без ошибок. Посмотрите на ограничение Addable. В скобках написано a + b. Условия ограничения выполняются тогда, когда значения a и b типа T допускают такую запись, то есть T имеет определённую операцию сложения:

template<class T>concept Addable =requires (T a, T b) {    a + b;};

Более сложный пример вызов функций swap и forward. Ограничение выполнится тогда, когда этот код скомпилируется без ошибок:

template<class T, class U = T>concept Swappable = requires(T&& t, U&& u) {    swap(std::forward<T>(t), std::forward<U>(u));    swap(std::forward<U>(u), std::forward<T>(t));};

Ещё один вид ограничений проверка корректности типа:

template<class T> using Ref = T&;template<class T> concept C =requires {    typename T::inner;     typename S<T>;         typename Ref<T>;   };

Ограничение может требовать не только корректность выражения, но и чтобы тип его значения чему-то соответствовал. Здесь мы записываем:

  • выражение в фигурных скобках,
  • ->,
  • другое ограничение.

template<class T> concept C1 =requires(T x) {    {x + 1} -> std::same_as<int>;};

Ограничение в данном случае same_as<int>
То есть тип выражения x + 1 должен быть в точности int.

Обратите внимание, что после стрелки идёт ограничение, а не сам тип. Посмотрите ещё один пример концепта:

template<class T> concept C2 =requires(T x) {    {*x} -> std::convertible_to<typename T::inner>;    {x * 1} -> std::convertible_to<T>;};

В нём два ограничения. Первое указывает, что:

  • выражение *x корректно;
  • тип T::inner корректен;
  • тип *x конвертируется к T::inner.

В одной строчке целых три требования. Второе указывает, что:

  • выражение x * 1 синтаксически корректно;
  • его результат конвертируется к T.

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

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

Ограничение для функции можно написать в трёх разных местах:

// Вместо слова class или typename в шаблонную декларацию.// Поддерживаются только концепты.template<Incrementable T>void f(T arg);// Использовать ключевое слово requires. В таком случае их можно вставить // в любое из двух мест.// Годится даже неименованное ограничение.template<class T>requires Incrementable<T>void f(T arg);template<class T>void f(T arg) requires Incrementable<T>;

И есть ещё четвёртый способ, который выглядит совсем магически:

void f(Incrementable auto arg);

Тут использован неявный шаблон. До C++20 они были доступны только в лямбдах. Теперь можно использовать auto в сигнатурах любых функций: void f(auto arg). Более того, перед этим auto допустимо имя концепта, как в примере. Кстати, в лямбдах теперь доступны явные шаблоны, но об этом позже.

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

Для класса возможностей меньше всего два способа. Но этого вполне хватает:

template<Incrementable T>class X {};template<class T>requires Incrementable<T>class Y {};

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

template<class T> void ReadAndFill(T& container, int size) {     if constexpr (requires {container.reserve(size); }) {         container.reserve(size);     }    // заполняем контейнер }

Эта функция будет одинаково хорошо работать как с vector, так и с list, причём для первого будет вызываться нужный в его случае метод reserve.

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

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

template<class T, class U>concept Derived = std::is_base_of<U, T>::value; template<Derived<Other> X>void f(X arg);

У концепта Derived два шаблонных параметра. В декларации f один из них я указал, а второй класс X, который и проверяется. Аудитории был задан вопрос, какой параметр я указал: T или U; получилось Derived<Other, X> или Derived<X, Other>?

Ответ неочевиден: это Derived<X, Other>. Указывая параметр Other, мы указали второй шаблонный параметр. Результаты голосования разошлись:

  • правильных ответов 8 (61.54%);
  • неправильных ответов 5 (38.46%).

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

Итак, я рассказал как определять новые концепты, но это нужно не всегда в стандартной библиотеке их уже предостаточно. На этом слайде приведены концепты, которые находятся в заголовочном файле <concepts>.



Это ещё не всё: концепты для проверки разных типов итераторов есть в <iterator>, <ranges> и других библиотеках.



Статус




Концепты есть везде, но в Visual Studio пока что не полностью:

  • GCC. Хорошо поддерживается с версии 10;
  • Clang. Полная поддержка в версии 10;
  • Visual Studio. Поддерживается VS 2019, но не полностью реализован requires.

Заключение


Во время трансляции мы опросили аудиторию, нравится ли ей эта функция. Результаты опроса:

  • Суперфича 50 (92.59%)
  • Так себе фича 0 (0.00%)
  • Пока неясно 4 (7.41%)

Подавляющее большинство проголосовавших оценило концепты. Я тоже считаю это крутой фичей. Спасибо Комитету!

Читателям Хабра, как и слушателям вебинара, дадим возможность оценить нововведения.
Подробнее..

Почему из команды уходит техписатель? У меня на это 5 причин

12.05.2021 16:20:09 | Автор: admin
Источник: ru.freepik.comИсточник: ru.freepik.com

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

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

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

Почему же такой человек в один прекрасный день может взять и уйти?

В этой статье хочу поделиться своим опытом, без отсылки на умные исследования Гарварда и Стэнфорда. Для себя выделила пять причин. Ими делюсь.

  1. Нет включения в командную работу.

  2. Нет обратной связи.

  3. Нет цели.

  4. Нет контроля.

  5. Нет ценности.

Заранее благодарю за комментарии и дополнения.

Причина 1. Нет включения в командную работу

Мы плывем в одной лодке. Слышали такое выражение у себя в команде? По-моему, это очень верное сравнение: работы команды над проектом в ИТ с работой экипажа корабля.

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

Источник: ru.freepik.comИсточник: ru.freepik.com

А теперь представьте, что одного из членов экипажа просто не замечают. Его не берут на общие собрания. Ему не передают никаких важных новостей. Никто не интересуется его проблемами и вопросами. Каково ему? Захочется ли ему выполнять свою работу? А если и захочется, будет ли и сможет ли он выполнять ее хорошо и с удовольствием?

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

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

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

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

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

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

Техписатель полноправный член экипажа на вашем корабле. Его ошибка может стоить успеха всего проекта. Поэтому вовлекайте его в проект полностью и всегда. А не только тогда, когда по вашему мнению должно быть начато документирование. Этим вы не только облегчите его работу, но и дадите почувствовать себя нужным человеком в команде. А это очень важно для качественного результата. Но вы это и сами знаете, да?

Причина 2. Нет обратной связи

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

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

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

Источник: ru.freepik.comИсточник: ru.freepik.com

А теперь поднимите руки те, у кого в команде так заведено. Особенно те, у кого техписатель один на всех.

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

Мы люди. И мы не можем всегда все делать правильно. Да еще и так, чтобы другим было понятно.

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

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

А еще правильная обратная связь поможет вашему техписателю развиваться и совершенствоваться. То же самое будет происходить и с документацией на вашем проекте. Ведь это ему не помешает, верно?

Причина 3. Нет цели

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

Поэтому задача написать хоть что-нибудь, просто потому что проект заканчивается, а о нем ни слова не написано, меня лично сбивает с толку.

Какая информация и от кого мне может понадобиться для создания такого документа? Какую проблему я решаю, когда мне нужно написать хоть что-нибудь? Кому я помогу, если я напишу хоть что-нибудь?

Источник: ru.freepik.comИсточник: ru.freepik.com

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

Поэтому: давайте будем ставить четкую задачу техписателю. Мол, нужно описание проекта, которое могло бы помочь ввести в курс дела новенького разработчика, который будет поддерживать этот проект. Например. Цель есть, проблему решаем. Всё отлично!

А если мы решили написать хоть что-нибудь для кого-нибудь, кого проект, возможно, но не факт, может заинтересовать, то и пары предложений будет вполне достаточно. И можно даже не трекать. Кому надо, тот и сам все сможет узнать, верно?

Причина 4. Нет контроля

На первый взгляд отсутствие контроля за работой это вух-ху! как здорово.

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

Главное сдай документ вовремя. Всё. Шикарно же, разве нет? Нет.

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

Когда у тебя задач пять, отодвинуть их в сторону и взять шестую с, конечно же, самым высоким приоритетом не сложно. Но а что если у тебя таких задач штук 10-15? И пусть 2-3 из них, ну, не срочные, но чем быстрее, тем лучше?

Ты оставляешь их в неопознанном статусе на неопределенное время. Потому что вникнуть в абсолютно новую задачу быстро не получится. Пока вопросы, пока ответы. А там глядишь, и до конца срока дня два осталось. А ты злишься-кипятишься и не укладываешься в них. (Дальше по сценарию.)

Источник: ru.freepik.comИсточник: ru.freepik.com

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

Да, самоорганизованность и дисциплина важные качества техписателя. Техписатель это самостоятельная боевая единица, как любил говорить один мой знакомый product owner. Но помните, что техписатель также член команды, работающей над проектом. Насколько же хорошо выполнит свою часть командной работы человек, которого оставили в одиночку разбираться с кучей высокоприоритетных задач?

Причина 5. Нет ценности

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

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

Первый: документация у вас будет, но качество ее будет сомнительным. Вашу команду такое устроит?

Второй: документация у вас будет и будет качественная, но в один не предвещающий ничего плохого день вы получите от вашего техписателя письмо с заявлением о добровольном увольнении. Когда вы на последней встрече 1 на 1 спросите у него, в чем дело, он ответит (если у вас доверительные отношения), что не ощущает, чтобы его работу ценили.

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

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

Поэтому: осознайте необходимость и ценность хорошей документации на вашем проекте уже сейчас. Спросите себя, зачем вам документация? Кто ее конечный пользователь? Какой она должна быть? Даже если вы не сможете дать четкие ответы на эти вопросы, не переживайте хороший и ответственный техписатель вам поможет. Но вы должны дать ему хоть какую-то информацию, а еще время и мотивацию для дальнейших исследований.

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

Источник: ru.freepik.comИсточник: ru.freepik.com

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

Удачи!

Подробнее..

Recovery mode Социальный эксперимент порядок из хаоса

14.05.2021 08:04:13 | Автор: admin

Бывало ли такое, что вы вас ограничивали за ваши мысли, так, что вы больше не могли высказаться в ответ? Весьма досадное чувство, не так ли? Как выстрел завершает жизнь человека, так и набор минусов способен лишить вас права существования на площадке.
Что будет если попытаться устроить общение по новым принципам, без администраторов, модераторов, без системы кармы, и даже без владельцев хоста? Сохранить свободу высказываний и при этом оградиться от хаоса? Я убежден что благодаря техническому прогрессу это стало возможно уже сегодня, и предлагаю на деле убедиться в этом, поучаствовав в эксперименте!

В чем суть?

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

(Лао-цзы)

Представьте себе затерянный телеграм чат, где нет владельца, и никто не был назначен модератором. У всех участников чата в фоновом режиме майнится некая валюта, просто по факту присутствия в чате, без регистрации. Благодаря встроеному в чат UX, валютой можно обмениваться и передавать друг другу, быстрее чем перевод в банке.
Ее также можно потратить чтобы закрепить свое сообщение на определенное время... или чтобы заблокировать спамера. Блокировка не удаляет человека, а лишь убирает ему поле ввода на время, в зависимости от затраченной на блокировку валюты. Система была бы несовершена без возможности отменить блокировку пользователю, точно также потратив на это часть своей накопленной валюты.

Звучит интересно, в чем отличие от кармы?

  1. Каждый может делать это! Нет инвайтов и все только в ваших и ваших друзей руках, нет централизованной точки отката, нет модератора который может затереть ваш пост или ограничить. Когда нет владельца, то нет и возможности для злоупотреблений "по праву владельца".

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

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

  4. Каждый может разбанить любого другого если у него достаточно валюты. Нет тотальной отмены с глубоким минусом, нет минуса которого нельзя отменить (как -100 на Хабре), нет лимитов прощения, было бы только желание подождать немного или попросить любого пользователя помочь вернуться сразу!

В чем цели эксперимента?

Проверить возможны ли новые, горизонтальные подходы во взаимодействии пользователей? Возможен ли отказ от иерархии? Можно ли общаться в интернете без концепции владения хостом? Можно ли автоматизировать модерацию? Успех эксперимента может стать толчком к расцвету таких систем. Эксперимент абсолютно некоммерческий, нет никакой рекламы, нет механизма извлечения выгоды. Я делаю это ради интереса посмотреть что получиться (и удовольствия пронаблюдать вышеописанную механику в действии).

Как поучаствовать?

Зайти в чат где все это реализовано: t.me/habr_experimental
В чате нет владельцев и админов, а вместо них подлючена и ждет наплыва пользователей вышеописанная система. Полагаю что тематика обсуждений может быть любая, на интересные целевой аудитории Хабра темы, и помните что никто ни в чем не может ограничить вас, кроме вас самих и таких же как вы людей.

Исходный код чата

Эта статья о социальном эксперименте, однако она была бы не для Хабра без технических деталей. Поэтому для тех кому это интересно, подробные принципы работы валюты и UX описаны в этой статье: habr.com/ru/post/556292/
Исходный код системы доступен на GitHub: github.com/demidko/timecobot
Для бекенда использован один из лучших виданных мною языков - Kotlin, за что хочу сказать здесь спасибо его разработчикам.

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

Подробнее..

Стандарт C20 обзор новых возможностей C. Часть 4 Ranges

19.05.2021 14:18:09 | Автор: admin


25 февраля автор курса Разработчик C++ в Яндекс.Практикуме Георгий Осипов рассказал о новом этапе языка C++ Стандарте C++20. В лекции сделан обзор всех основных нововведений Стандарта, рассказывается, как их применять уже сейчас, и чем они могут быть полезны.

При подготовке вебинара стояла цель сделать обзор всех ключевых возможностей C++20. Поэтому вебинар получился насыщенным. Он растянулся почти на 2,5 часа. Для вашего удобства текст мы разбили на шесть частей:

  1. Модули и краткая история C++.
  2. Операция космический корабль.
  3. Концепты.
  4. Ranges.
  5. Корутины.
  6. Другие фичи ядра и стандартной библиотеки. Заключение.

Это четвёртая часть, рассказывающая о новом модуле стандартной библиотеки, Ranges.

Ranges


До этого рассматривалось ядро языка. Теперь я расскажу про изменение в стандартной библиотеке, которое не добавляет нового в синтаксис, введённый C++20 заголовочный файл <ranges>.



Мотивация


В C++ много стандартных алгоритмов. Но они применимы не всегда. Если действие нестандартное, то для его решения, скорее всего, придётся вводить некрасивые вложенные циклы, флаги. При этом код лавинообразно теряет выразительность.

Слушателям предлагался вопрос. Сколько строк выведет код ниже?

  1. 5
  2. 6
  3. 9
  4. Ни одной.
  5. Будет выводить, пока не остановим.

Подумайте, прежде чем прочитать ответ.

#include <iostream>int main() {    const int days = 3;   // количество дней с играми    const int games = 2;  // количество игр с питомцем в день    for (int i = 0; i < days; i++) {        std::cout << "День " << i << std::endl;        for (int j = 0; j < games; i++) {            std::cout << "  Игра " << j << std::endl;        }    }}

Во время вебинара правильных ответов оказалось больше, чем я ожидал. Это тест на внимательность, потому что в коде есть ошибка: цикл никогда не завершится. Проблема в том, что я перепутал инкрементируемую переменную во внутреннем цикле. Допустить такую ошибку куда проще, чем её заметить. Если вы ни разу так не ошибались, вряд ли вы программируете на C/C++.

Другой пример. Стандартные алгоритмы принимают два итератора: на первый элемент и на последний, фиктивный. Но передавать пары утомительно. Например, алгоритм merge, который смешивает два отсортированных диапазона, требует сразу пять итераторов две пары и ещё один выходной. Приходится дублировать имя контейнера. Вполне возможно, что контейнер назван не одной буквой, а длинным именем или выражением:

std::merge(  collection_holder.get_left_collection().begin(),   collection_holder.get_left_collection().end(),   collection_holder.get_right_collection().begin(),   collection_holder.get_right_collection().end(),  std::back_inserter(    collection_holder.get_destination_collection()  ));

Ошибиться в такой конструкции несложно. Код стал бы более выразительным, если бы вместо пары итераторов передавался один диапазон.

Ещё один пример для мотивации. Для стандартных действий есть алгоритм, скажем, copy_if, который копирует элементы, удовлетворяющие условию. Он используется для фильтрации элементов. Алгоритм transform применяет к каждому элементу функцию. Предположим, нужно выполнить обе операции: отфильтровать элементы и к оставшимся применить функцию. Такой алгоритм можно назвать transform_if, но к сожалению, в стандартной библиотеке его нет.

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

std:vector<int> numbers_in;std:vector<int> numbers_out;// задача: поделить на 2 все чётные числа из numbers_in// и записать результаты numbers_outstd:vector<int> intermediate;// скопируем в intermediate только чётные числаstd::copy_if(numbers_in.begin(), numbers_in.end(),               std::back_inserter(intermediate),              [](int x) {                        return x % 2 == 0;             });// поделим их на 2std::transform(intermediate.begin(), intermediate.end(),               std::back_inserter(numbers_out),               [](int x) {                          return x / 2;               })

Тут пришлось завести промежуточное хранилище. Получили неэффективное решение с двумя проходами по элементам.

Что у других


В Python есть классная фича: можно писать прямо в выражениях квадратные скобки и делать внутри всё что угодно, в том числе фильтровать элементы и применять к ним функции. Это замечательно и удобно. Возможно, Ranges в C++ делали, поглядывая на Python.

Пример с transform_if сокращается до одной строки:

# transform_if в одну строку средствами языка:numbers_out = [x // 2 for x in numbers_in if x % 2 == 0]

Обычные циклы упрощаются в Python. Пример, в котором я допустил ошибку, мог бы выглядеть так:

days = 3   # количество дней с играмиgames = 2  # количество игр с питомцем в деньfor i in range(days):    print("День %d" % i)    for j in range(games):        print("  Игра %d" % j)

В Python не нужно писать i = 0; i < N; ++i. Буква i набирается один раз, и возможности перепутать что-либо у вас нет. Кстати говоря, range даёт не контейнер, который содержит все элементы, а генерирует числа на лету. По производительности это если и будет уступать обычному циклу, то едва-едва.

Приведу преимущества Python списком:

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

Другой пример SQL. Хотя это не язык программирования, мы можем реализовать transform_if даже на нём:

SELECT n / 2 FROM tab WHERE n % 2 == 0;

Код получается вполне выразительным.

Примеры


В C++20 появилась возможность решать проблемы, озвученные в начале статьи, это библиотека Ranges. Например, так выглядят циклы привычные for, которые перебирают все целые числа в некотором интервале:

#include <iostream>#include <ranges>namespace rng = std::ranges;namespace view = rng::views;int main() {    const int days = 3;   // количество дней с играми    const int games = 2;  // количество игр с питомцем в день    for (int i : view::iota(0, days)) {        std::cout << "День " << i << std::endl;        for (int j : view::iota(0, games)) {            std::cout << "  Игра " << j << std::endl;        }    }}

Теперь не придётся три раза писать i, три раза писать j, и нельзя их перепутать. Вместо привычных циклов с инкрементом итерируемся по std::ranges::views::iota. Как и в Python, функция не будет генерировать контейнер, а выдаст числа на лету.

Range упрощает реализацию transform_if:

#include <iostream>#include <ranges>#include <vector>namespace rng = std::ranges;namespace view = rng::views;int main() {    auto even = [](int i) { return i % 2 == 0; };    auto half = [](int i) { return i / 2; };        std::vector<int> numbers_in = {100, 55, 80, 2, -1};    auto numbers_out = numbers_in | view::filter(even) |  // <-- вся магия                 view::transform(half);        for (auto i : numbers_out) {        std::cout << i << std::endl; // 50, 40, 1    }}

Здесь различные преобразования комбинированы операцией |, или как её ещё называют, pipe. filter, отфильтровывающий нечётные числа, комбинирован с transform, делящим на два. Получаем объект-диапазон, по которому можно итерировать. Этот объект ленивый: он не будет ничего вычислять, пока вы не запросите первое значение. Более того, вернув первое значение, диапазон не будет вычислять второе до тех пор, пока оно не будет запрошено. Это позволяет не хранить в памяти все значения единовременно и применять алгоритмы в один проход. Замечательная функция.

Но если всё же вам необходимо вычислить всё сразу, вы можете по старинке сложить все элементы диапазона в какой-нибудь контейнер: numbers_vector = std::vector(number_out.begin(), numbers_out.end()).

На этом слайде приведено сравнение, как это пишется в C++20, а как в Python. Видно, что Python по-прежнему лаконичнее, но всё-таки C++ уже гораздо ближе.



Такие возможности появились в C++20, и это классно. Разумный вопрос: а что с производительностью?

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

В варианте с вызывается функция iota. Каждую итерацию будет что-то вычисляться. Возможно, будет оверхед.

Я сделал бенчмарк для сравнения цикла в старом стиле с itoa. Его результат на слайде:



Различия в производительности нет! Оказывается, что цикл с itoa настолько же эффективен, как и простой с инкрементом переменной.

При добавлении сложного синтаксического сахара производительность часто падает. Но только не в C++.

Ещё один бенчмарк, в котором сравнивается transform_if в старой реализации и в новой на основе <ranges>.



Как видно, c Ranges получилось быстрее. Справедливости ради скажу, что если написать функцию вручную с циклом, итерирующимся по контейнеру, то получится ещё небольшой прирост скорости. Я не знаю, в чём причина. Наверное, это будет исправлено в следующих версиях Ranges.

Антон Полухин предложил исключить динамическую аллокацию, возникающую при создании вектора, а заодно и сам вектор. Теперь кстати, вычисление и суммирование выполняется в один проход. Результат подобрался очень близко к ручному способу, но всё-таки немного проигрывает.

Ещё примеры


Это было только начало. В Ranges ещё масса интересного.

Вот код, который сортирует элементы вектора и выводит их:

#include <iostream>#include <vector>#include <algorithm>#include <ranges>namespace rng = std::ranges;template <rng::input_range Range>void Print(const Range& range) {    std::cout << "Elements:";    for (const auto& x : range) {        std::cout << ' ' << x;    }    std::cout << std::endl;}int main() {    std::vector v = { 4, 1, 7, 2, 3, 8 };    rng::sort(v);    Print(v); // Elements: 1 2 3 4 7 8    return 0;}

Заметьте, что здесь применяется не обычный алгоритм std::sort, а sort из пространства имён std::ranges. В этот алгоритм можно передать не пару итераторов, а контейнер то, чего и хотелось.

Я написал функцию Print, которая использует возможности концептов. Используется концепт input_range из пространства имён std::ranges. Он нужен в шаблонной функции для того, чтобы она принимала только объекты-диапазоны с точки зрения Ranges.

В C++20 этот код можно упростить:

void Print(const rng::input_range auto& range) {    std::cout << "Elements:";    for (const auto& x : range) {        std::cout << ' ' << x;    }    std::cout << std::endl;}

Слово template убирается и становится неявным. А const auto& это тип параметра, к нему применён концепт input_range.

Ещё одно заметное преимущество новых алгоритмов в библиотеке <ranges> это параметр проекции. Предположим, что вам требуется написать сортировку по некоторому полю объекта:

struct Lecture {    int course;    int local_idx;    int complexity;};std::vector<Lecture> ReadLectures();int main() {    std::vector<Lecture> lectures = ReadLectures();    // как раньше    std::sort(lectures.begin(), lectures.end(),          [](const Lecture& lhs, const Lecture& rhs) {            return lhs.complexity < rhs.complexity;    });    return 0;}

Пришлось разработать свой компаратор и дублировать название поля complexity. В <ranges> добавлены новые реализации старых алгоритмов, которые помимо передачи диапазона допускают параметр-проекцию. Такой алгоритм применит заданную вами функцию и сравнит её результаты вместо сравнения элементов контейнера напрямую:

struct Lecture {    int course;    int local_idx;    int complexity;};std::vector<Lecture> ReadLectures();namespace rng = std::ranges;int main() {    std::vector<Lecture> lectures = ReadLectures();    // как теперь    rng::sort(lectures, std::less<>{}, [](const Lecture& x) {        return x.complexity;    });    return 0;}

В качестве компаратора взят обычный std::less, который сравнивает, применяя операцию <, но благодаря проекции применяется он не к элементам вектора, а к значениям лямбда-функции.

Теория


На этом слайде приведены новые алгоритмы из пространства имён std::ranges. Работа Комитета впечатляет: 85 алгоритмов, каждый из которых тщательно проработан.



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

Вернёмся к примеру с transform_if.

auto range = numbers_in | view::filter(even) |             view::transform(half);

Мы отфильтровали вектор numbers_in и применили к его элементам функцию. Имена filter и transform примеры адаптеров, то есть таких объектов Ranges, которые меняют диапазон.

В библиотеке есть несколько видов адаптеров. Адаптер drop отбрасывает элементы, а take ограничивает их количество. Предположим, нам нужны элементы с 5-го по 14-й. На SQL это было бы сделано так:

SELECT * FROM tab LIMIT 10 OFFSET 5

На C++ теперь можно сделать похожим образом:

using namespace view = rng::views;for (const auto& x : tab | view::drop(5) | view::take(10)) {    std::cout << x << std::endl;}

Адаптеров в стандартной библиотеке не так много, как алгоритмов, а жаль. Вот список всех: all, filter, transform, take, take_while, drop, drop_while, join, split, counted, common, reverse, elements, keys, values.

Зато можно создавать свои! Этот пример кода я не буду разбирать подробно. Посмотрите, как просто мы создали адаптеры для выделения разных категорий пользователей и комбинировали их:

auto ByGender(Gender gender) {    return view::filter([gender](const Person& person) {        return person.gender == gender;     });}auto ByEmployment(bool is_employed) {    return view::filter([is_employed](const Person& person) {        return person.is_employed == is_employed;     });}template <rng::ForwardRange Range>AgeStats ComputeStats(Range&& persons) {    auto females = ByGender(Gender::FEMALE);    auto males = ByGender(Gender::MALE);      auto employed = ByEmployment(true);    auto unemployed = ByEmployment(false);    return {        ComputeMedianAge(persons),        ComputeMedianAge(persons | females),        ComputeMedianAge(persons | males),            ComputeMedianAge(persons | females | unemployed),        ComputeMedianAge(persons | males | employed)     };}

Статус




Ranges это нововведение стандартной библиотеки. У каждого компилятора есть своя родная реализация.

  • К сожалению, в библиотеке Clang диапазоны пока не реализованы.
  • В библиотеке Visual Studio 2019 присутствует поддержка <ranges>, но частично. Например, нет некоторых стандартных алгоритмов.
  • В библиотеке GCC уже всё хорошо, и <ranges> можно использовать смело.

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

Заключение


Во время вебинара мы спросили у аудитории, нравится ли эта функция. Результаты опроса:

  • Суперфича 21 (80,77%)
  • Так себе фича 2 (7,69%)
  • Пока неясно 3 (11,54%)

Больше всего разочаровывает в Ranges небольшое количество стандартных адаптеров. Например, в Python есть функция enumerate, которая к элементу приписывает его порядковый номер. Там есть возможность итерироваться по декартову произведению парам элементов разных диапазонов. Есть zip, при котором итерирование будет происходить по диагонали декартова произведения. Ничего подобного в C++ я не нашёл. Будем надеяться на новые выпуски Стандарта.
Их добавляют в C++23.
Антон Полухин
Но в целом мне диапазоны нравятся, хотя я понимаю, почему некоторые зрители вебинара не оценили их. Наверное, многим это нововведение кажется сложным. Но мы привыкнем ведь пишем на C++ и разбирались и не с таким.

Одно могу сказать точно: Ranges изменит стиль программирования очень многих вещей. И это здорово, потому что код станет более понятным, а программы более надёжными!

Читателям Хабра, как и слушателям вебинара, дадим возможность оценить нововведения.
Подробнее..

Зачем нам p3express в наших IT-проектах

20.05.2021 10:09:10 | Автор: admin

Зачем нам p3express в наших IT-проектах

Нас всего 6 человек и по сути мы проектный офис. Мы стремимся меньше делать своими руками, но больше проектировать и организовывать работы. А это проекты, проекты и еще раз проекты, которые у нас завязаны на IT-разработку разработка web и мобильных приложений, промо и контент проекты, автоматизация бизнес-процессов и сопровождение стартапов.

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

Конечно, у кого-то из заказчиков есть свои стандарты управления проектами, но заточены они под их основную деятельность (например, для строительства домов), и пытаться с их помощью руководить IT-проектом такое себе приключение. Поэтому методологию ведения их ИТ-проектов обычно выбираем мы. Выбор у нас всегда был большой есть прекрасные классические инструменты, которые охватывают всё, что только можно охватить, плюс подходят к этому с разных сторон и классно документированы:

Но есть нюанс все они требуют очень высокого уровня владения стандартом со стороны клиента, чтобы мы сработались при использовании разных с ним подходов. А это будет сложно, если клиент исповедует PRINCE2, а мы, например, топим за ISO 21500.

Другая сложность в том, что подходить к реализации проекта можно с трех сторон:

Всё жестко зафиксировано с самого начала и ничего менять нельзя. То есть мы говорим: У нас есть сроки, деньги и то, что должно в итоге получиться. Шаг влево/вправо расстрел. А проект мы считаем успешным, только если достигли вот такой цели. Это классно и замечательно, но часто даже сам клиент не готов к тому, чтобы все его требования были жестко зафиксированы в самом начале и чтобы потом их нельзя было менять. Всё равно в процессе зайдет речь о каких-то изменениях и корректировках. А если при этом вы не договорились, что это повлечет за собой изменение бюджетов, сроков или объема работ будет больно.

Другой подход говорит, что мы будем удовлетворять клиента и это Agile. Что бы клиент ни захотел, какие бы идеи у него ни рождались, мы будем работать, работать, и конца этому видно не будет пока все не станут счастливы. Agile был первым, о чем мы подумали, когда выбирали подход, потому что он действительно прекрасен, а Agile-манифест это вообще сказка и прелесть: важнее люди и взаимодействие, работающий продукт важнее документации, и самое главное сотрудничество и готовность к изменениям:

Но, оказывается, на моменте готовности к изменениям большая часть клиентов Agile-манифест не поддерживает. Как не поддерживает ни одна компания, которая работает в B2B секторе и занимается заказной разработкой, потому что у них есть своя бюрократия и прочие факторы. Так что Agile мы оставили только для своих стартап-проектов.

А для клиентов у нас прижился ценностный (сбалансированный) подход это когда в конце проекта мы с заказчиком соглашаемся, что игра стоила свеч. Даже если результат может быть получен не совсем тогда, использоваться могут не совсем те деньги, и может быть, получилось не совсем то. Но если мы смогли договориться, что это стоило затраченных усилий и нашли баланс это он и есть:

Используя этот подход, мы постепенно пришли и к тому, что для взаимодействия на одном языке с клиентами нужна общая проектная методология. Обязательно с низким порогом входа чтобы даже никогда не управляя проектами или используя другую методологию, вы могли бы быстро прочитать описание и сказать: Да, классно, я всё понял, поехали! Но под эти требования ни Agile, ни другие взрослые методологии не подходили. Зато подошел фреймворк p3express.

В p3express мы пришли с огромным накопленным багажом проектных инструментов. От некоторых он помог нам избавиться. Но большая часть осталась с нами, так как никаких противоречий с новым фреймворком не выявилось. И в принципе, я сейчас буду рассказывать не столько про p3express в его первозданном виде, сколько уже про то, как мы поженили свои практики с тем скелетом (фундаментом), которые он дает.

У p3express есть бешеное преимущество: он простой. Это 37 шагов, разрисованных на картинке и быстро читаемых, при этом есть примеры и шаблоны. Прочитать их за 10 минут вполне реально. Хотя, конечно, без опыта не получится начать управлять проектом прямо сразу, здесь и сейчас. Но получится понять, допустим, меня, когда я буду описывать, чем мы завтра будем заниматься, и вообще куда и как мы двигаемся. То есть если мы договорились, что работаем по p3express, то всем в любой момент времени будет понятно, как мы будем жить и куда пойдем.

Второе его преимущество p3express сбалансирован по цене/срокам/скоупу.

И еще один кайф (впрочем, как у многих других стандартов) это фреймворк. Он не описывает жестко всё, что мы должны делать (то есть не ограничивает и не сковывает), а говорит: примерно такие вопросы и такие задачи нужно решить примерно таким способом.

Дальше я поэтапно рассмотрю шаги p3express и прокомментирую, как мы с этим живем.

Подготовка проекта

Начало в p3express вполне классическое:

  • Шаг 01. Определить спонсора;

  • Шаг 02. Подготовить резюме проекта;

  • Шаг 03. Определить руководителя проекта;

  • Шаг 04. Развернуть рабочее пространство;

  • Шаг 05. Определить команду;

  • Шаг 06. Планирование проекта;

  • Шаг 07. Определить внешних исполнителей (если в проекте они есть) ;

  • Шаг 08. Провести аудит подготовки;

  • Шаг 09. Да/нет;

  • Шаг 10. Провести стартовую встречу;

  • Шаг 11. Фокусированная коммуникация.

У нас же получилось всё сильно сложнее, чем 11 шагов.

Шаг 01. Определить спонсора продукта

p3express не дает четкого определения: спонсор продукта это его владелец или нет? но в его контексте это синонимы. В других методологиях это слово тоже по-разному трактуется: это может быть тот, кто принимает решение или получатель или менеджер проекта. В каждом фреймворке есть своя терминология, и что даже важнее у каждого из нас в компании есть своя терминология, которую мы считаем той самой общепринятой. А у ребят в соседнем офисе она будет совершенно другая.

По моему мнению, владельцем является тот, кто за него платит и кто получает от него основную выгоду. На практике же это часто разные люди. Почему владелец продукта нам, как менеджерам, важен с практической точки зрения? Потому что это тот этап, когда мы спрашиваем: Кто будет определять, мы сделали всё хорошо и правильно, или нет? Кто будет принимать проект? И часто бывает, что деньги платят одни, а решение о том, заплатить эти деньги или нет, принимают другие люди. Это абсолютно нормальная история (делегирование и пр.), но нам нужно понимать, кто выставляет основные требования.

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

Шаг 02. Подготовить резюме проекта

Для нас это самое сложное перед запуском проекта. Взрослые методологии, тот же самый ISO 21500, предполагают, что на вход в проект придет бизнес-план или ТЭО, которые полностью описывают, что мы делаем и зачем, как на этом планируем зарабатывать и т.д., чтобы можно было прочитать и сказать: А, понятно!, и по нему уже запускать проект. Но у нас так не получается.

Поэтому перед стартом проекта мы обычно делаем очень много консалтинга. Эти работы мы даже выносим в отдельный контракт с фиксированной стоимостью. Обычно это относительно небольшое время от 2 до 6 недель при том, что проекты бывают от 2 до 12-24 месяцев.

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

Со стартапами мы обычно используем Lean Canvas. Это большая таблица, в которой грубо раскидано что, зачем, кому мы делаем, как нам за это будут платить и почему нам это выгодно. Это больше маркетинговая история, но на самом деле именно она определяет, что мы будем делать. Это некая канва бизнес-модели, и именно с ней мы сверяемся, когда хотим что-то в проекте поменять или выбрать альтернативный путь. Мы смотрим нашему продукту это ценности прибавит или, наоборот, убавит?

Из Lean Canvas вырастает MVP: мы видим, каким должен быть минимальный продукт, чтобы проверить, а правильно ли мы вообще напридумывали скетчи и прототипы, концепт дизайна, техническое задание? Это как раз тот пакет документов, который в больших методологиях называется бизнес-план, ТЭО или еще как-то.

И в таком виде на входе у нас появляется резюме проекта, о котором и говорит p3express для того, чтобы понимать что и зачем мы делаем. И часто мы делаем сильно не то, что было описано в первоначальном брифе.

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

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

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

Параметры проекта

В итоге для любого вида бизнеса мы создаем описание проекта по таким параметрам:

Это есть во всех стандартах управления проектами, которые я знаю. Но мы используем очень простую методику Scope-Pak. Придумали ее не мы по ссылке в QR коде можно посмотреть первоисточник:

Scope-Pak это 8 шагов по 5-7 вопросов каждый. На них лучше всего отвечать всем вместе то есть собираем нужных людей, задаем им вопросы и фиксируем ответы. На этом этапе желательно, чтобы команда заказчика еще не была сформирована, так как именно в процессе встречи с теми людьми, которые могут вам помочь, вы поймете, кого из них брать в команду.

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

Рассмотрим кратко эти 8 шагов:

Шаг 1. Заинтересованные стороны:

  • Чьи деньги участвуют в реализации проекта?

  • Этот человек является спонсором проекта?

  • Кто еще будет участвовать в проекте?

Шаг 2. Компоненты:

  • Что предстоит сделать?

  • Нужны какие-то вспомогательные работы?

  • Нужны подготовительные работы?

  • Завершающие работы?

  • Если мы сделаем все это, мы завершим весь проект?

Когда мы читали оригинал, мы очень смеялись над советом: ОГРАНИЧЬТЕ СПИСОК 30 ПУНКТАМИ то есть не расписывайте подробнее, чем на 30 пунктов, что надо сделать. А на практике мы столкнулись с тем, что только первые 6 рождаются просто в бешеных муках, а потом сложно остановиться.

Шаг 3. Цели и результаты:

  • Зачем мы все это делаем и как правильно это назвать?

  • Что мы получим на выходе и как это измерить?

  • Когда мы хотим это получить?

  • То, что мы запланировали сделать даст нам эти результаты?

Наверное, этим меня и зацепил Scope-Pak. Обычно делается все наоборот: сначала говорят о целях, а потом что мы будем делать ради этого. А когда мы сначала спрашиваем: Что мы делаем?, а потом: Зачем? появляется ступор, ведь у клиента в голове был только один план надо сделать это, это и это. Ответ помогает нам с заказчиком и командой выйти из ступора и перейти к пункту: А может, можно пойти другим путем?

Шаг 4. Альтернативы

  • Есть ли более эффективный способ достичь своих целей?

  • То, что мы запланировали сделать единственный способ получить нужный нам результат?

  • Как еще можно получить тот же результат?

  • Что можно сделать лучше?

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

Шаг 5. Ресурсы и сложности

  • Какова стратегия финансирования проекта?

  • Насколько он важен в сравнении с другими проектами?

  • Какие ресурсы вам потребуются?

  • С какими препятствиями вы столкнетесь?

  • Кто спонсирует этот проект?

  • Какие разрешения вы должны получить?

  • Кто будет выполнять задания проекта?

  • Каковы временные рамки?

  • Каковы критические даты?

  • Что может быть еще включено в проект?

  • Что можно исключить из проекта?

Забавно то, что когда-то дубль вопроса Кто спонсирует? попал сюда по ошибке из первого шага, но на практике получилось, что он здесь к месту. Потому что часто выясняется, когда мы наконец расписали, с кем что согласовывается спонсоры не совсем те. Поэтому мы оставили этот вопрос здесь, он классно помогает.

Шаг 6. План наступления

Тут просто укрупненно накидываем взаимосвязи шагов, что от чего зависит:

Шаг 7. Риски:

  • Какие предположения вы сделали?

  • Какие предположения вы должны сделать?

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

  • Как можно сократить риски или найти обходные пути?

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

Шаг 8. Ключевые индикаторы достижения цели:

  • Кто 3-4 самые главные заинтересованные участники проекта?

  • Какой результат их скорее всего удовлетворит?

  • Как измерить каждый из них по завершении проекта?

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

Например, заказчик хочет оптимизировать логистику. Мы выясняем, что сейчас эффективность использования его автотранспорта 20%, а клиент хочет достигнуть 70%. Мы считаем на коленке и понимаем, что весь его процесс так устроен, что больше 30% просто не получится. Потому что хоть клиент и ожидает, что машина будет 70% в пути, ей на самом деле нужно больше времени для приезда, разгрузки, погрузки, отъезда и прочих факторов. И если мы соглашаемся на 70%, не оговаривая всё это сразу, то под конец приходим к тому, что проделали отличную работу, всё здорово, всё классно, все довольны, а клиент говорит: Ребята, ну не 70 же! Как минимум, это неприятно, а может закончиться и контрактными проблемами.

Шаг 9. Да / Нет

Этот шаг описан и в p3express, во многих других методологиях. Для нас он о честности. Потому что когда предварительные работы проведены, мы даем заказчику полный и честный расклад по предстоящему проекту. Бывает иногда соблазн нарисовать более радужную картинку, но это нечестно и обязательно выйдет нам боком плохие новости всё равно всплывут. Честно это не украшать картинку и не обещать, что всё будет обалденно, шикарно и классно. Может и будет, но надо понимать, сколько это будет стоить это тот самый сбалансированный подход.

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

Поэтому я согласен с тем, что этап Да/Нет должен происходить как раз на этом шаге. Этим мне тоже очень понравился p3express, потому что это мало где применяется. По некоторым методологиям, люди посидели, подумали и ТЭО составили, а потом принесли на старт проект и сразу начали проектировать. А в жизни как раз получается наоборот. Когда назначен менеджер и решили да, наверное, будем делать проект, очень многое еще непонятно. И вот именно на этом этапе есть смысл сесть и подумать а вы уверены, что в это ввязываетесь? Да? Тогда поскакали, всё классно, и все друг друга хорошо понимают.

Планирование этапа

Тут у P3express всё по канонам:

  • Шаг 12. Обновить планы;

  • Шаг 13. Определить внешних исполнителей (если в проекте они есть);

  • Шаг 14. Да/нет;

  • Шаг 15. Провести стартовую встречу цикла;

  • Шаг 16. Фокусированная коммуникация.

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

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

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

Дополнительно на этапе планирования мы делаем Lean-приоритезацию она поможет в случае наступления рисков остаться в ценностных рамках. Лучше всего это делать вместе с будущим владельцем проекта и/или с лицами, принимающими решение. Схема очень простая: по двум шкалам (ценность/сложность) оцениваем по 10-балльной шкале все компоненты (фичи и прочее, что решили делать):

  • какую ценность нам это принесет?

  • что будет стоить по трудозатратам, по ресурсам, по времени, etc.?

Получаем табличку. Иногда бывает, что ценно всё то есть все наши компоненты получают десятки. Это нехорошо, и мы тогда пытаемся их оценить по 100-балльной шкале и тут уже все компоненты обычно делятся на 4 категории (очень редко бывает, что какой-то из квадратиков остается пустым).

Здесь я опять возвращаюсь к тому подходу, что обычно наша задача не попасть день в день, доллар в доллар и строчка в строчку, а определить и создать основную ценность. А для этого нам в процессе надо понимать, какие задачи и какие требования мы (в случае чего) можем выкинуть, но ценность сохранить. Lean-приоритезация нам дает для этого те самые приоритеты. Если мы знаем, что это стоит больше, а то меньше, то ради второго можно пожертвовать первым, но не наоборот.

Реализация этапа

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

Еженедельные действия p3express определяет так:

  • Шаг 17. Оценить прогресс;

  • Шаг 18. Работать с отклонениями;

  • Шаг 19. Еженедельная встреча;

  • Шаг 20. Провести еженедельный аудит;

  • Шаг 21. Фокусированная коммуникация.

То есть каждую неделю нужно готовить отчет по статусу. Для этого мы используем отчет из очень немолодой книжки Управление проектом на одной странице К. А. Кэмбэлла она маленькая, но в ней ценные вещи написаны, а формат отчетов вообще шикарный. Мы показываем клиенту вот такой отчет на одной странице, классный и вкусный, и в нем видно практически всё:

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

Два показателя особенно классные: плановый объем (PV) и освоенный объем (EV). Они помогают нам наглядно увидеть: отстаем ли мы, идем с опережением или что-то другое происходит.

Как это работает? Ресурсы редко тратятся линейно, поэтому обычно мы не можем утверждать, что за половину сроков мы потратим половину денег. На самом деле это почти всегда не так. Например, есть задачи, где в начале идет что-то очень емкое (необязательно это айтишная история) какая-то концепция, дизайн-исследование что угодно. Мы это делаем в первую неделю, а потом три недели тестируем и согласовываем то есть в это время ценности уже не добавляется, а время это занимает. Или наоборот сначала долго, но дешево копим данные, а потом быстро и дорого их анализируем. В этом случае первые 3 недели мы ничего не тратим, никакой ценности не приносим, а в конце тратим много ресурсов (денег), но получаем много ценности.

Из-за этой неровности невозможно сопоставить сроки и объем. Вроде бы прошла половина срока, и мы должны получить половину планируемого результата но мы получили 63% или 48%. Возникает вопрос: Это хорошо или плохо?. А по методике соответствия планового/освоенного мы заранее расписываем: мы будем тратить ресурсы именно так, и именно так получать ценность. А потом легко сравнить, получились ли наши запланированные 63% и 48%.

Ежедневные действия

На этом этапе p3express в основном предлагает работать с рисками:

  • Шаг 22. Зафиксировать RICs;

  • Шаг 23. Реагировать на RICs;

  • Шаг 24. Принять готовые продукты.

Мы их дополнили частью из SCRUMа, введя ежедневные митинги для обсуждения:

  • Что сделал вчера;

  • Что планируешь сегодня;

  • Что может помешать.

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

Закрытие этапа

Вот так это в p3express:

  • Шаг 25. Оценить удовлетворённость заказчика и команды;

  • Шаг 26. Запланировать улучшения;

  • Шаг 27. Фокусированная коммуникация.

Если у нас проект в один этап мы это пропускаем и переходим к закрытию проекта. Если этапов несколько, то вопрос в том, как именно оценивать удовлетворенность этапом. Мы пробовали использовать анкету для оценки из шага 25, но не зашло. Потому что когда мы получаем заполненную анкету, на нее всегда надо реагировать, хорошая она или плохая надо разбираться, выяснять или просто дать ответ. Не всегда это нужно, если мы сделали всю предыдущую работу нормально. К тому же дополнительные вопросы часто людей раздражают: Мы и так все проблемы знаем! Но, может быть, я еще не умею это готовить. Знаю ребят, у которых анкета шикарно заходит, и они очень довольны.

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

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

Закрытие проекта

По p3express закрытие включает такие шаги:

  • Шаг 28. Получить одобрение и передать продукт

  • Шаг 29. Передать проект

  • Шаг 30. Оценить удовлетворенность заказчика и команды

  • Шаг 31. Провести аудит закрытия

  • Шаг 32. Извлечь уроки и заархивировать проект

  • Шаг 33. Объявить и отметить окончание проекта

  • Шаг 34. Фокусированная коммуникация

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

Сессия Скажи спасибо

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

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

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

После проекта

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

  • Шаг 35. Оценить полученные выгоды

  • Шаг 36. Спланировать дополнительные действия

  • Шаг 37. Фокусированная коммуникация

Мы называем это стратегической сессией. Для стартапов она будет впервые за время проекта, а для бизнеса уже второй. На ней мы корректируем KPI, обновляем ожидания от проекта, составляем план развития и едем дальше. В идеале запускаем новый проект.

Такие регулярные сессии особенно важны, если проект длится годами. У нас был проект, который начался с лендинга, длился три с половиной года и в итоге перерос в огромную онлайн-академию с кучей народу, всякими бонусами, баллами и прочими фишками. За это время в проекте поменялось всё. И если бы мы не дробили его на маленькие кусочки и не проводили регулярные стратегические и проблемные сессии, то нам было бы сложно оставаться в рамках стратегии, планов и нормальных человеческих отношений.


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

Подробнее..

Перевод Хватит организовывать код по типу файлов

06.06.2021 12:22:20 | Автор: admin

Какой самый популярный стиль организации кода вы встречали в корпоративных кодовых базах? Лично я чаще всего видел решение, подразумевающее группировку всех файлов по их типу. Таким образом, к примеру, в системе MVC все контроллеры, все сервисы, все репозитории, все POJO и так далее находятся вместе. Давайте назовем такое решение "стековым" стилем организации кода.

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

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

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

Неправильная абстракция

Люди не читают код по назначению файлов и классов. Никто никогда не говорит: "покажите мне весь API проекта" или "продемонстрируйте мне все запросы, отправляемые решением". Люди читают код, полагаясь на его смысл и роль. Как в системе управления гостиницами, например, люди отдельно думают о номерах, гостях, ценах и так далее.

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

В нашем примере с управлением гостиницей, организованном смысловым стилем, весь код, связанный с гостями (независимо от технического назначения), помещён в один пакет, весь код, связанный с номерами, - в другой и так далее. Каждый из этих пакетов может иметь свою собственную внутреннюю организацию в стиле "стека" или просто несколько классов на одном уровне. Это позволяет легко найти все, что связано, скажем, с гостями, в одном месте.

Нарушения связи

Многие разработчики считают, что "стековая" организация все же выигрывает, отделяя разные слои кода друг от друга. Чтобы найти необходимые классы или файлы на любом уровне проекта, нужно просто перейти к слою, содержащему эти уровни. Это, безусловно, способствует разделению слоев друг от друга.

Проблема этого аргумента в том, что он фокусируется на разделении, но полностью игнорирует потребность в связи между определёнными структурами. Допуская, что все файлы и классы определённого типа в такой системе расположены вместе, справедливо ли будет сказать, что их взаимная связь, как структур одинакового назначения, но разного смысла, нас устраивает? Положено ли все же, к примеру, контроллерам, находиться отдельно от своих классов и репозиториев? Можем ли мы позволить, скажем, всем репозиториям быть сильно зависимыми друг от друга, но отделенными от уровня сервисов? Очевидный ответ - НЕТ! Такой код стал бы хрестоматийным куском г*вна. Рефакторинг такой системы на более мелкие решения был бы абсолютным кошмаром, потому что вам пришлось бы отделить друг от друга все классы на каждом уровне стека. Это убивает основную цель использования стиля MVC.

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

Трудно менять

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

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

Ограничивает выбор дизайна

Поскольку код организован из соображений функциональности, он ограничивает возможности людей подходить к дизайну системы. Например, поскольку логика предметной области должна относиться к "сервисам", разработчики противятся использованию правильно разделённых конструкций и запихивают все в сервисы, создавая тем самым кошмарные классы длиной в тысячи строк.

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


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

Подробнее..

Стандарт C20 обзор новых возможностей C. Часть 6 Другие фичи ядра и стандартной библиотеки. Заключение

08.06.2021 16:18:29 | Автор: admin


25 февраля автор курса Разработчик C++ в Яндекс.Практикуме Георгий Осипов рассказал о новом этапе языка C++ Стандарте C++20. В лекции сделан обзор всех основных нововведений Стандарта, рассказывается, как их применять уже сейчас и чем они могут быть полезны.

При подготовке вебинара стояла цель сделать обзор всех ключевых возможностей C++20. Поэтому вебинар получился насыщенным. Он растянулся на почти 2,5 часа. Для вашего удобства текст мы разбили на шесть частей:

  1. Модули и краткая история C++.
  2. Операция космический корабль.
  3. Концепты.
  4. Ranges.
  5. Корутины.
  6. Другие фичи ядра и стандартной библиотеки. Заключение.

Это шестая, заключительная часть. Она рассказывает о других нововведениях ядра и стандартной библиотеки, добавленных Стандартом C++20.

Другие фичи ядра


Я рассказал о самых значительных нововведениях Стандарта, но это только капля в море C++20. Перейдём к менее глобальным, но не менее интересным вещам. Подробно останавливаться на каждой не буду, потому что цель обзора рассказать пусть не всё, но обо всём.

Шаблоны


Многое из нововведений Стандарта касается шаблонов. В C++ шаблонные аргументы делятся на два вида: типовые и нетиповые. Типовые названы так неспроста: их значение тип данных, например int, контейнер, ваш класс, указатель. Нетиповые шаблонные аргументы это обычные значения, вычисляемые на этапе компиляции, например число 18 или true. В C++17 возможности нетиповых шаблонных параметров были сильно ограничены. Это могло быть числовое значение, bool, enum-тип или указатель. C++20 расширил список и позволил передавать в качестве шаблонного аргумента объект пользовательского класса или структуры. Правда, объект должен удовлетворять ряду ограничений.

Пример:

struct T {    int x, y;};template<T t>int f() {    return t.x + t.y;}int main() {    return f<{1,2}>();}

Статус:
GCC , CLANG , VS 


Ещё из нового крутые возможности вывода шаблонного типа класса. Не буду комментировать, просто оставлю пример. Кому интересно разберитесь:

template<class T> struct B {    template<class U> using TA = T;    template<class U> B(U, TA<U>);  //#1}; B b{(int*)0, (char*)0}; // OK, выведен B<char*>


Статус:
GCC , CLANG , VS 


Лямбды


Раньше в лямбда-функциях было три вида скобок. Теперь их может быть четыре стало возможным писать явные параметры для лямбда-функций:

  1. квадратные скобки для переменных связывания,
  2. угловые скобки для шаблонных параметров,
  3. круглые скобки для списка аргументов,
  4. фигурные скобки для тела функции.

Порядок важен: если его перепутать, будет ошибка. Если шаблонных параметров нет, то угловые скобки не пишите, потому что пустыми они быть не могут. Кстати, эта фича уже нормально поддерживается во всех компиляторах.

int main() {    auto lambda = []<class T>(T x, T y){                                return x * y - x - y; };    std::cout << lambda(10, 12);}


Статус:
GCC , CLANG , VS 


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

int main() {    using LambdaPlus3 = decltype([](int x) {    return x + 3;    });    LambdaPlus3 l1;    auto l2 = l1;    std::cout << l2(10) << std::endl; // 13}

Статус:
GCC , CLANG , VS 

Также в C++20 можно использовать лямбды в невычислимом контексте, например внутри sizeof.

Compile-time


Появился новый вид переменных constinit. Это некоторая замена static-переменным. Локальные static-переменные могут быть проинициализированы во время первого обращения, что иногда нежелательно. А вот constinit инициализируются по-настоящему статически. Если компилятор не смог проинициализировать такую переменную во время компиляции, код не соберётся. По Стандарту constinit-переменная может быть также thread_local.

const char* g() { return "dynamic initialization"; }constexpr const char* f(bool p) { return p ? "constant "      "initializer" : g(); } constinit const char* c = f(true); // OKint main() {    static constinit int x = 3;    x = 5; // OK}

Удивительно, но constinit-переменная не обязана быть константной. Константным и constexpr обязан быть её инициализатор.

Статус:
GCC , CLANG , VS 


И у функций тоже есть новый вид consteval. Это функции, которые вычисляется исключительно во время компиляции. В отличие от constexpr, которые могут вызываться как в run-time, так и в compile-time, эти функции не получится даже вызвать во время выполнения, будет ошибка.

consteval int sqr(int n) {    return n * n;}constexpr int r = sqr(100);  // OK int x = 100;int r2 = sqr(x); // <-- ошибка: результат не константаconsteval int sqrsqr(int n) {    return sqr(sqr(n));}constexpr int dblsqr(int n) { return 2*sqr(n); } // <-- ошибка, constexpr может                                                  // вычисляться в run-time

Многие слушатели вебинара не поняли смысла этой фичи. Зачем нужен ещё один constexpr. Но представьте действие, которое имеет смысл только во время компиляции. Например, вы положили в проект файлы ресурсов и во время компиляции их читаете. Пока что так делать нельзя, поэтому просто представьте. В run-time этих ресурсов уже не будет.

Статус:
GCC , CLANG , VS 

В C++20 очень существенно расширили сам constexpr, внутри него теперь можно вызывать даже виртуальные функции! А ещё, что особенно замечательно, многие контейнеры стали поддерживать constexpr.

Новые синтаксические конструкции


Мы ждали их ещё с 1999 года. Всё это время программисты на чистом C дразнили нас, демонстрируя, как они могут ими пользоваться, а мы нет. Вы уже поняли, о чём речь? Конечно, о designated initializers, или обозначенных инициализаторах!

Теперь, конструируя объект структуры, можно явно написать, какому полю присваивается какое значение. Это очень круто. Ведь для структур с 1015 полями понять, что чему соответствует, практически невозможно. А такие структуры я видел. Кроме того, поля можно пропускать. Но вот порядок менять нельзя. И нельзя ещё несколько вещей, которые можно в C. Они приведены в примере.

struct A { int x; int y; int z; }; A b{ .x = 1, .z = 2 };A a{ .y = 2, .x = 1 }; // <-- ошибка  нарушен порядокstruct A { int x, y; };struct B { struct A a; };int arr[3] = {[1] = 5};     // <-- ошибка  массив   struct B b = {.a.x = 0};    // <-- ошибка  вложенныйstruct A a = {.x = 1, 2};   // <-- ошибка  два вида инициализаторов

Статус:
GCC , CLANG , VS 

Ещё крутое нововведение, которое забыли добавить девять лет назад инициализатор в for по диапазону. Ничего хитрого тут нет, просто дополнительная возможность для for:

#include <vector>#include <string>#include <iostream>int main() {    using namespace std::literals;    std::vector v{"a"s, "b"s, "c"s};    for(int i=0; const auto& s: v) {        std::cout << (++i) << " " << s << std::endl;    }}

Статус:
GCC , CLANG , VS 

Новая конструкция using enum. Она делает видимыми без квалификации все константы из enum-а:

enum class fruit { orange, apple };enum class color { red, orange };void f() {    using enum fruit; // OK    using enum color; // <-- ошибка  конфликт}

Статус:
GCC , CLANG , VS 


Другое


  • Операция запятая внутри [] объявлена как deprecated. Намёк на что-то интересное в будущем.
GCC , CLANG , VS 
  • Запрет некоторых действий с volatile-переменными. Эти операции тоже объявлены как deprecated. Переменные volatile сейчас часто используются не по назначению. Видимо, комитет решил с этим бороться.
GCC , CLANG , VS 
  • Агрегатные типы можно инициализировать простыми круглыми скобками ранее были допустимы только фигурные.
GCC , CLANG , VS 
  • Появился уничтожающий оператор delete, который не вызывает деструктор, а просто освобождает память.
GCC , CLANG , VS 
  • Слово typename в некоторых случаях можно опускать. Лично меня нервировала необходимость писать его там, где оно однозначно нужно.
GCC , CLANG , VS 
  • Теперь типы char16_t и char32_t явно обозначают символы в кодировках, соответственно UTF-16 и UTF-32. Ещё добавили новый тип char8_t для UTF-8.
GCC , CLANG , VS 
  • Различные технические нововведения. Если я что-то упустил пишите в комменты.

Другие фичи стандартной библиотеки


Это были нововведения ядра, то есть то, что меняет синтаксис самого C++. Но ядро даже не половина Стандарта. Мощь C++ также в его стандартной библиотеке. И в ней тоже огромное число нововведений.

  • В <chrono> наконец-то добавлены функции работы с календарём и часовыми поясами. Появились типы для месяца, дня, года, новые константы, операции, функции для форматирования, конвертации часовых поясов и много магии. Этот пример из cppreference оставлю без комментариев:

#include <iostream>#include <chrono>using namespace std::chrono; int main() {    std::cout << std::boolalpha;     // standard provides 2021y as option for std::chrono::year(2021)    // standard provides 15d as option for std::chrono::day(15)     constexpr auto ym {year(2021)/8};    std::cout << (ym == year_month(year(2021), August)) << ' ';     constexpr auto md {9/day(15)};    std::cout << (md == month_day(September, day(15))) << ' ';     constexpr auto mdl {October/last};    std::cout << (mdl == month_day_last(month(10))) << ' ';     constexpr auto mw {11/Monday[3]};    std::cout << (mw == month_weekday(November, Monday[3])) << ' ';     constexpr auto mwdl {December/Sunday[last]};    std::cout << (mwdl == month_weekday_last(month(12), weekday_last(Sunday))) << ' ';     constexpr auto ymd {year(2021)/January/day(23)};    std::cout << (ymd == year_month_day(2021y, month(January), 23d)) << '\\n';}// вывод: true true true true true true


Статус:
GCC , CLANG , VS 


  • Целая новая библиотека format. Про неё также можно послушать в докладе у Антона Полухина. Теперь в C++ есть современная функция для форматирования строк с плейсхолдерами. Библиотека позволит делать подобную магию:

auto s1 = format("The answer is {}.", 42); // s1 == "The answer is 42."auto s2 = format("{1} from {0}", "Russia", "Hello"); // s2 == "Hello from Russia"int width = 10;int precision = 3;auto s3 = format("{0:{1}.{2}f}", 12.345678, width, precision);// s3 == "    12.346"

Она обещает быть куда более производительной, чем вывод в поток stringstream, но тем не менее не лишена проблем. Первая проблема: format не проверяет все ошибки, и вообще, на данном этапе не разбирает формат в compile-time. Это очень огорчает.
Сейчас в комитете хотят это поправить с бэкпортированием функционала в C++20.
Антон Полухин
Вторая проблема: пока не реализован ни в одной стандартной библиотеке, проверить в деле нельзя.

За время, прошедшее с вебинара, format успели реализовать в Visual Studio.

Статус:
GCC , CLANG , VS 


  • Потрясающие новости: теперь в Стандарте есть . Помимо него добавлено обратное , число Эйлера, логарифмы некоторых чисел, корни и обратные корни, корень из вместе с обратным, постоянная Эйлера Маскерони и золотое сечение. Все они доступны при подключении <numbers> в пространстве имён std::numbers.

Статус:
GCC , CLANG , VS 

  • Новые алгоритмы: shift_left и shift_right. Они сдвигают элементы диапазона на заданное число позиций. При этом закручивания не происходит: элементы, уходящие на край, не телепортируются в другой конец, а уничтожаются. С другого края возникают пустые элементы из них был сделан move.

Статус:
GCC , CLANG , VS 

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

Статус:
GCC , CLANG , VS 

  • Ещё одна несложная функция in_range. Она позволяет проверить, представимо ли целое число значением другого типа:

#include <utility>#include <iostream> int main() {    std::cout << std::boolalpha;     std::cout << std::in_range<std::size_t>(-1)               << '\\n'; // false, так как отрицательные числа не представимы в size_t    std::cout << std::in_range<std::size_t>(42)               << '\\n'; // true}

Статус:
GCC , CLANG , VS 

  • make_shared стал поддерживать создание массивов.

Статус:
GCC , CLANG , VS 

  • Добавились операции сравнения для неупорядоченных контейнеров unordered_map и unordered_set.

Статус:
GCC , CLANG , VS 

  • Новая функция std::to_array делает array из C-массива или строкового литерала.

Статус:
GCC , CLANG , VS 

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

Статус:
GCC , CLANG , VS 

  • Отличное нововведение: многие функции и методы стали constexpr. Теперь его поддерживают контейнеры, такие как string, vector.

Все алгоритмы из <algorithm>, не выделяющие память, стали constexpr. Можно сортировать массивы и делать бинарный поиск на этапе компиляции :)
Антон Полухин

Статус:
GCC , CLANG , VS 

  • Появился новый тип span. Он задаёт указатель и число количество элементов, на которые указывает указатель.

istream& read(istream& input, span<char> buffer) {    input.read(buffer.data(), buffer.size());    return input;}ostream& write(ostream& out, std::span<const char> buffer) {    out.write(buffer.data(), buffer.size());    return out;}std::vector<char> buffer(100);read(std::cin, buffer);

span позволяет заменить два параметра функции одним. Он чем-то похож на string_view это тоже лёгкая оболочка, которая может представлять элементы контейнеров. Но набор допустимых контейнеров больше это может быть любой линейный контейнер: вектор, std::array, string или C-массив. Ещё одно отличие от string_view он позволяет модификацию элементов, если они не константного типа. Важно, что модификацию только самих элементов, но не контейнера.

Статус:
GCC , CLANG , VS 


  • Ещё одно замечательное нововведение файл <bit>. Он добавляет большое количество возможностей для манипуляций с беззнаковыми числами на битовом уровне. Теперь функции вида определить количество единиц в бинарном числе или двоичный логарифм доступны из коробки. Эти функции перечислены на слайде.




Также файл определяет новый тип std::endian. Он, например, позволяет определить, какая система записи чисел используется при компиляции: Little endian или Big endian. А вот функций для их конвертации я, к сожалению, не нашёл. Но в целом считаю, что <bit> очень крутое нововведение.

Статус:
GCC , CLANG , VS 


  • Дождётся тот, кто сильно ждёт! Этот цитатой можно описать многое из Стандарта C++20. Поздравляю всех, мы дождались: у string теперь есть методы starts_with и ends_with для проверки суффиксов и постфиксов. А также другие методы контейнеров и функции, с ними связанные:
    • метод contains для ассоциативных контейнеров. Теперь можно писать my_map.contains(x) вместо my_map.count(x) > 0 и всем сразу понятно, что вам нужно проверить наличие ключа;
    • версии функции std::erase и std::erase_if для разных контейнеров;
    • функция std::ssize для получения знакового размера контейнера.

Статус:
GCC , CLANG , VS 

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

void f(int* p) {   int* p1 = std::assume_aligned<256>(p);}

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

Статус:
GCC , CLANG , VS 


  • Добавился в Стандарт и новый вид потоков osyncstream в файле syncstream. В отличие от всех остальных потоков, osyncstream одиночка: у него нет пары на букву i. И это не случайно. Дело в том, что osyncstream всего лишь обёртка. Посмотрите на код:

#include <thread>#include <string_view>#include <iostream>using namespace std::literals;void thread1_proc() {    for (int i = 0; i < 100; ++i) {        std::cout << "John has "sv << i                   << " apples"sv << std::endl;    }}void thread2_proc() {    for (int i = 0; i < 100; ++i) {        std::cout << "Marry has "sv << i * 100                  << " puncakes"sv << std::endl;    }}int main() {    std::thread t1(thread1_proc);    std::thread t2(thread2_proc);    t1.join(); t2.join();}

В его выводе наверняка будет подобная абракадабра:

Marry has John has 24002 applesJohn has 3 applesJohn has 4 applesJohn has 5 applesJohn has 6 applesJohn has 7 apples puncakesJohn has 8 apples

Вывод каждого отдельного элемента производится атомарно, но разные элементы всё равно перемешиваются между собой. osyncstream исправляет ситуацию:

...#include <syncstream>...void thread1_proc() {    for (int i = 0; i < 100; ++i) {        std::osyncstream(std::cout) << "John has "sv << i                                     << " apples"sv << std::endl;    }}void thread2_proc() {    for (int i = 0; i < 100; ++i) {        std::osyncstream(std::cout) << "Marry has "sv << i * 100                                     << " puncakes"sv << std::endl;    }}...


Теперь все строки выведутся корректно. Этот поток не будет выводить ничего, пока не вызовется деструктор объекта: все данные он кеширует, а затем выполняет одну атомарную операцию вывода.

Статус:
GCC , CLANG , VS 


  • В Стандарт добавился набор из шести новых функций для сравнения целых чисел:
    • cmp_equal,
    • cmp_not_equal,
    • cmp_less,
    • cmp_greater,
    • cmp_less_equal,
    • cmp_greater_equal.

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

-1 > 0u; // true

По правилам в подобном случае знаковый операнд преобразуется к беззнаковому значению: 0xFFFFFFFFu для 32-битного int. Функция cmp_greater позволит обойти эту особенность и выполнить настоящее математическое сравнение:

std::cmp_greater(-1, 0u); // false

Статус:
GCC , CLANG , VS 

  • Ещё одно нововведение source_location. Это класс, который позволит заменить макросы __LINE__, __FILE__, используемые при логировании. Статический метод current этого класса вернёт объект source_location, который содержит строку и название файла, в котором этот метод был вызван. Тут я задал вопрос. Какое число выведет функция со слайда?



Есть два варианта:

  • число 2, что соответствует строке, где source_location написан;
  • число 7, что соответствует строке, где функция log вызвана.

Правильный ответ 7, где вызвана функция, хоть это и кажется неочевидным. Но именно благодаря этому обстоятельству source_location можно использовать как замену макросам __LINE__, __FILE__ для логирования. Потому что, когда мы логируем, нас интересует не где написана функция log, а откуда она вызвана.

Статус:
GCC , CLANG , VS 


  • Закончим обзор на радостной ноте: в C++ существенно упростили многопоточное программирование.
    • Новый класс counting_semaphore ждём, пока определённое количество раз разблокируют семафор.
    • Классы latch и barrier блокируют, пока определённое количество потоков не дойдёт до определённого места.
    • Новый вид потоков: jthread. Он делает join в деструкторе, не роняя вашу программу. Также jthread поддерживает флаг отмены, через который удобно прерывать выполнение треда stop_token. С этим флагом связаны сразу несколько новых классов.
    • Ещё один новый класс atomic_ref специальная ссылка, блокирующая операции других потоков с объектом.
    • Возможности atomic значительно расширены. Он теперь поддерживает числа с плавающей точкой и умные указатели, а также новые методы: wait, notify_one и notify_all.

Статус:
GCC , CLANG , VS 


Заключение


Рассказ о фичах C++ 20 окончен. Мы рассмотрели все основные изменения, хотя на самом деле в Стандарте ещё много разного и интересного. Но это уже технические особенности, которые не обязательно знать каждому профессиональному программисту.

Вполне возможно, я что-то упустил тогда добро пожаловать в комментарии.
C++ на этом не останавливается, Комитет по стандартизации активно работает. Уже было заседание, посвящённое Стандарту 2023 года. То, что в него уже включили, нельзя назвать киллер-фичами. Но ожидания от нового Стандарта большие. Например, в него войдут контракты и полноценная поддержка корутин.

На Хабре круто встретили предыдущие части. В статьях про Модули и Ranges развернулись особо оживлённые дискуссии. Будет здорово, если вы расскажете о своих впечатлениях от C++20 и ожиданиях от новых стандартов. Например, какую фичу C++20 вы считаете самой крутой и важной? Чего больше всего ждёте от будущего языка? Приветствуются также дополнения, уточнения, исправления наверняка что-то важное я упомянуть забыл.

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

Поживем увидим.

Опрос


Читателям Хабра, в отличие от слушателей вебинара, дадим возможность оценить нововведения.
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru