Возвращение к C++

Последние лет 6 я всё меньше и меньше занимался разработкой на C++, количество использования фактически шло по убывающей до нулевого значения год назад. Чего только не было в качестве основного языка, и Go, и Elixir и даже небольшие отрезки времени чистый Python. Но так случилось, что с переходом на новое место работы C++ вновь стал моим основным рабочим инструментом. Появилась насущная необходимость шустро освежить знания в голове и, в идеале, совместить это с чем-то полезные. В итоге я решил решил порешать задачки на тему криптографии от cryptopals дабы как-то скрасить ожидание открытия заинтересовавшего меня курса по криптографии на Коурсере.  Ну а так как теперь мне действительно есть с чем сравнивать C++, ощущения от языка получаются более цельные, как мне кажется. Continue reading

C++ идет в облака

Попасть на CppCon в этом году по ряду причин не вышло, поэтому я смотрю видео на YouTube. В процессе просмотра списка докладов глаз моментально зацепился за The Design of the C++ Runtime for AWS Lambda и я не разочаровался. Доклад в чем-то знаковый, так как он показывает применимость языка в области о которой C++ разработчики не думают и, обычно, ничего не знают.

Ключевые моменты из доклада:

  • AWS SDK for C++ позволяет оперировать всеми сервисами AWS, SDK доступен на GitHub. Там же можно найти огромное количество примеров использования.
  • SDK использует libCURL и разработчик должен сам разобраться с инициализацией хранилища сертификатов, расположение которого, конечно же, может зависеть от версии Linux.
  • Много воевали с libC, который довольно объемный с точки зрения набора библиотек и дистрибутиво-зависимый. Остановились на решении паковать все файлы проекта (включая libC) в один архив и запускать через ld-linux.so.
  • Если хочется уменьшить количество файлов привносимых libC, хотя целесообразность этого действия под вопросом так как еще есть libC++/libStdC++, то можно воспользоваться musl.
  • AWS гарантирует минимальный уровень процессора SkyLake, так что если вам нужен SIMD, то вполне можно включать процессоро-специфические оптимизации.

При том, что один из основных сценариев использования лямбды это – по-быстрому что-то посчитать, причем “по-быстрому” тут ключевое ведь оплата за время, то потенциал использования C++ (еще и с включенными SIMD-оптимизациями) на этом поприще выглядит очень заманчивым.

Rust и не звездные команды

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

Continue reading

Форумы умерли, да здравствует Slack

Когда я только добрался до интернета, а сделал я это довольно поздно, судя по дате регистрации на РСДН-е я активен в сети с года так 2006, то был восхищён профессиональными форумами. Это было место с реальной движухой, там были умные люди, они обсуждали интересные вопросы и вообще жизнь кипела ключом. Время шло, форумы стали отмирать. Какие-то стали местом обсуждения политики, какие-то годятся только на то, что бы замерять у кого длиннее, где-то принято плакаться на тяжелую жизнь и мечтать свалить, а какие-то годятся только для мастурбации на карму. Когда-то активные завсегдатаи говорят что куда интереснее обсудить политику или похвастаться большой ЗП, нежели поговорить про дело… а для дела есть StackOverflow, где уже на все вопросы давно ответили. Я никогда не понимал как можно сравнить форум и SO, ведь SO – это про вопрос/ответ и все дискуссии строго пресекаются, а форум был в первую очередь про дискуссию. Можно еще вспомнить про Reddit, но по мне так это скорее коллекция ссылок, нашел что-то интересное, запостил даже не потрудившись пары предложений со своими мыслями добавить, а тебе почесали ЧСВ поставив плюсики.

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

C++ интервью && многопоточность

В рамках поддержки формы и необходимости размяться перед серьезным поиском работы я походил по разным собеседованиям и надо сказать, вопросы по многопоточности в связке с С++ на них стали появляться. Очень редко по сравнению с количеством вопросов по сортировке гномиков и прочей ересью, но тем не менее за этот год я столкнулся аж с 2 вопросами из этой области в компаниях, которые активно используют C++11 и выше. Что удивительно, некоторые до сих пор сидят на С++98, а то и на вообще Си-с-классами.
Continue reading

Основная головная боль в мире C++

В процессе обсуждения увлекательного вопроса “за что не любят современный C++” всплыл интересный список последствий UB оптимизаций. В отличие от довольно простого управления памятью которое мы получили начиная с C++14, UB – это действительно ужас-ужас, который фактически не реально держать в голове.

Великолепный пример с переполнением при умножении i на миллиард, который позволяет компилятору сильно “упростить” цикл:
Continue reading

CppCon 2018

В этом году мне посчастливилось в третий раз оказаться на конференции CppCon. Как и в прошлые годы, на конференции можно найти интересные доклады из практически любой области применения C++. Если сравнивать с конференциями прошлый лет, то в 2018 году вышло на уровне 2016, просто конференция 2017 была особенно прекрасной по содержанию 🙂
Внезапно самыми интересными для меня в этом году оказались не доклады Гуру С++, которые на этом деле собаку съели, а выступления не замеченных мной ранее докладчиков.
  1. Текущая ситуация, когда сообщество информационной безопасности стоит особняком от сообщества разработчиков, мне кажется в корне не верной и доклад Software Vulnerabilities in C and C++ как раз был направлен на устранение данного безобразия. Это просто замечательное начинание, так как конференции типа BlackHat и PHdays скучны для разработчиков, а сами безопасники к нам не ходят. В результате образуется нелепый вакуум, хотя в теории оба сообщества должны тесно работать друг с другом.
  2. Идея доклада Better C++ using Machine Learning on Large Projects вроде и лежит на поверхности, но решились реализовать такое только в Ubisoft Montreal. Суть идеи проста: у нас есть история коммитов и история ошибок. А что будет если их объединить и натренировать сеть? Может даже получиться не только предсказать будет ли в коммите дефект (с довольно хорошей вероятность 75%), но и автоматом предложить код с исправлением?
  3. Как неожиданно выяснилось, прямой конкурент Maya и 3D MAX пишет команда из 25 человек и очень успешно занимается этим последний 21 год. Вызовы и их решение в докладе Patterns and Techniques Used in the Houdini 3D Graphics Application.
  4. Довольно хороший рассказ про организацию сборочного пайплайна (правда у нас лучше вышел) в докладе Big Infrastructure at a Small Scale.
  5. Многопоточность – боль для очень и очень многих включая меня. What do you mean “thread-safe”? обобщает вопросы связанные с безопасностью разработки многопоточного кода на концептуальном уровне. В вроцессе много думал и планирую пересмотреть.
Остальное интересное и не очень:
  1. Начиналось все со Страуструпа и Concepts: The Future of Generic Programming. Скучно, как и все виденные мной предыдущие его выступления, но не пойти на Самого тоже никак.
  2. Очень-очень хороший доклад от Kate Gregory Simplicity: not just for beginners. Хорош он в первую очередь тем, что призывает и доступно объясняет что же такое простой код, к которому все разработчики должны стремиться.
  3. Доклад Саттера как-то смутно отложился в голове, вроде всё здорово и увлекательно, но… то-ли “но к чему это”, то-ли “а зачем столько лишних слов” не давали мне покоя на докладе Thoughts on a More Powerful and Simpler C++. Самое главное что я из него вынес и собираюсь как можно скорее опробовать флаг -Wlifetime, пиару которого была посвящена половина этого доклада. Да, вторая половина про метаклассы, которые постепенно начинают принимать очертания и лет через 10 мы их получим, если повезет.
  4. Закрывал конференцию доклад про нашумевшую уязвимость Spectre: Secrets, Side-Channels, Sandboxes, and Security с живой демкой и кучей ассемблерного кода. Было невероятно интересно и познавательно.
  5. Часто задавался вопросом “как же работает отладчик”, но ленился найти на него ответ и тут всё взяли да рассказали на How C++ Debuggers Work. Про отладчики было вообще много, как потому что  Backtrace активно пиарятся, так и потому, что писать нормально поставить процесс разработки на C++ выходит сильно не у всех.
К сожалению я упустил целую кучу потенциально интересных докладов, которые теперь жду на YouToube:
  1. Git, CMake, Conan – How to ship and reuse our C++ projects и Debug C++ Without Running я пропустил из-за энергичного и очень посредственного доклада Александреску Expect the Expected.
Ну а самым разорчаровывающим докладом где, как мне кажется, никто не понял зачем докладчик вообще вышел на сцену был Interfaces matter: High Performance and Heap Allocated Containers. В итоге вместо часа доклад уложился в 30 минут и вопросов не было от слова совсем, так как единственные вопрос “а к чему тут это все было?” как-то не удобно задавать…
Удивительным изменением в этом году было количество рускоговорящих на конференции, по моим прикидкам около 10, может быть 15% от общего числа посетителей. В итоге мы весело и познавательно посидели небольшой компанией в человек 20 в баре перед отъездом, жаль только из Касперского на конференции я никого из знакомых не увидел.

С++ и надежный, безопасный код

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

Единый стиль форматирования

Казалось бы, единый стиль форматирования проекта – это мелочь, но ведь не просто так почти каждая уважающая себя компания имеет увесистый документ “BestCompanyInTheWorld Coding Standard”, который как минимум на половину состоит из того, как код должен быть отформатирован. При этом, код в BestCompanyInTheWorld почти наверняка отформатирован вразнобой, так как применение стандарта контролируется в лучшем случае в процессе ревью, но кто же помнит все эти хитросплетения пробелов и скобок? Работая с Go я впервые оценил прелесть того, что весь код включая сторонние библиотеки действительно написан в едином стиле, так как существует единое правило форматирования для всего языка. Эта казалось бы мелочь очень сильно упрощает работу над чужой кодовой базой и в случае с Go легко достигается автоматически при помощи доступных по умолчанию форматтеров.
Continue reading

IDE и C++

Я довольно давний поклонник IDE от Jetbrains. Тем же IntelliJ IDEA и PyCharm просто нет сопоставимых альтернатив с точки зрения скорости работы и удобства. Собственно говоря у меня у меня даже подписка на них оформлена из соображений “нравится проект – поддержи финансово”, но вот с CLion что-то пошло не так…

На мой взгляд основная проблема в том, что разработчики и менеджеры продукта пришедшие с платформ .NET и JVM просто не понимают что такое разработка на C/C++. В итоге идёт попытка переложить модель разработки с той же Java на C++. В крайне случае у меня сложилось именно такое ощущение как после личного общения с JetBrain-овцами на CppCon, так и после вчерашнего диалога в Twitter.

Собственно, проблема и непонимание состоит в том, что команда CLion упорно хочет видеть “проектную модель”. Я не знаю чем это вызвано, толи наличием libClang под капотом, толи архитектурными проблемами собственного парсера, но без реальной проектной модели CLion превращается в тыкву. Хотя, он даже и с реальной проектной моделью иногда превращается в тыкву, например спотыкаясь на сгенерированном через Protobuf коде.

К сожалению, такой подход не может работать в мире C++ на многих проектах сложнее Hello World. За исключением счастливчиков, которым доступно писать всё в Visual Studio, у разработчиков огромный зоопарк используемых редакторов и причина у этого довольно грустная, в теории CLion и должен был исправить эту ситуацию. Так вот, мои коллеги пишут в Sublime, Emacs, Vim, Eclipce CDT, Studio Code и многих других редакторах по большому счету потому, что все они практически одинаково плохи в роли C++ IDE. Ну может за исключением Emacs/Vim, за счёт его интеграции с Globals/CTags и Eclipse, за счёт наличия грамотно реализованного парсера C++. Но в Emacs/Vim ещё нужно уметь писать – это свой отдельный мир, а Eclipse даже на Xeon-ах с горой памяти на борту умудряется тормозить.

Если же говорить о проектной модели и почему привязка к ней делает редактор не пригодным к промышленному использованию – то её часто просто нет. К примеру на данный момент я периодически переключаюсь между несколькими проектами: один на базе CMake, второй на некой дикой смеси Make, CMake и SCons обвешанной sh/bat скриптами сверху. Так же я иногда заглядываю в проекты которые представляют из себя кучу файлов просто “для консультации”. Таким образом, в теории, я мог бы писать 1 проект из всех над которыми работаю в CLion, но есть ли в этом хоть какой-то смысл если мне нужно писать и другие проекты и иметь пусть приблизительную, но быструю навигацию по коду и хоть какую-то автоподстановку? По мне так никакого, так как привыкать к особенностям 2-х редакторов куда как менее удобно нежели всегда работать в одном. Жаль только надежда на то, что на менеджеров продукта CLion сойдет понимание проблемы угасла.

Эксперименты с Rust

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

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

Подготовка к работе

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

Установка

Сам компилятор и набор утилит типа cargo устанавливается и обновляется очень легко и удобно, особенно на UNIX-ах. Всего одна консольная команда в соответствии с официальной документацией. Windows никогда особо дружелюбным для разработчиков не был, хотя и тут разработчики Rust постарались и сделали как поддержку GNU toolchains, так и поддержку MSVC. Всё заработало “из коробки”, что несказанно меня удивило. Ощущение зрелости как минимум системы доставки и развертывания однозначно присутствует.

Редактор

В моём случае с редактором было всё просто: взять Vim да установить пару-тройку дополнений к нему. Подсветка и форматирование работают отлично, автодополнение, базирующееся на racer, работает сносно. Как я понял, все остальные редакторы и IDE также используют racer для автодополнения и ожидать какого-то чуда за пределами VIM не следует. Понадобилось всего два плагина: rust.vim и vim-racer. В обоих случаях они снабжены достаточно подробной документацией и никакой сложности установка и настройка не вызывает.

Особо хотелось бы отметить наличие rustfmt, который позволяет форматировать код в едином стиле. Впервые я проникся любовью к такого рода приложениям, начав работать с Go, где весь код автоматически форматируется одним единственным правильным способом. В командной работе практика оказалась невероятно удобной, так как из “стандарта кодирования” команды полностью исчезает пункт про форматирование, при этом весь код выглядит одинаково, что облегчает понимание и работу с чужими фрагментами/модулями. После этого я внедрил у нас использование clangformat на C++ проектах (правда уже с единым набором правил для форматирования), что также сделало разработку ощутимо комфортнее.

Также в Vim большой популярностью пользуется плагин Tagbar, который не умеет работать с Rust из коробки, но это очень легко исправляется.

Еще одним потенциально полезным компонентом экосистемы Rust мне показался cargo-outdated, позволяющий отслеживать устаревшие зависимости. Ну просто мечта разработчика C++ какая-то, особенно учитывая то, что сторонние компоненты (дополнения) Rust устанавливаются при помощи cargo очень простым способом:

cargo install rustfmt
cargo install racer
cargo install cargo-outdated

Создание проекта

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

cargo new --bin ddump-gen

И у меня есть новый проект, в котором, путем добавления всего двух строчек, я могу работать с libclang:

[dependencies]
clang = "0.16.0"

Это интересно само по себе хотя бы тем, что изначально я порывался написать тот же проект на C++, но бросил уже на стадии написания cmake-файла для этой же самой libclang.

Разработка

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

Доступные библиотеки

То, что Rust активно пиарится Mozilla и Samsung в течении последних лет, очень положительно сказалось на количестве доступных новых библиотек, а также оберток для уже существующих библиотек из мира C/C++. В результате очень быстро подобралась подходящая обертка над libClang, был найден удобный парсер командной строки и подходящий логгер. Довольно удивительно, но на решение тех же вопросов на C++ я бы потратил даже больше времени, чем в совершенно незнакомой экосистеме.

Про язык

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

Собственно говоря, к чему весь этот разговор про обработку ошибок. При отсутствии исключений в языке размер кода растет, так как, во-первых, появляется необходимость проверять коды возврата и не ожидать, что “исполнилось корректно либо выполнение было прервано”, а во-вторых, теряется возможность сделать обобщенную обработку нескольких потенциальных ошибок в одном блоке. Если задуматься над причиной, то её можно сформулировать как “мне нужно писать больше кода, но лень”. Есть ли в такой необходимости что-то хорошее? Опыт с Go подсказывает, что есть! Адресная обработка ошибок, т.е. сразу после возникновения ошибочной ситуации, обычно более качественно продумана и лучше покрыта диагностикой по сравнению с обобщенными исключениями. Кроме того, в стандартной библиотеке Rust пошли чуть дальше и добавили немного синтаксического сахара. Особо полезными, на мой взгляд, являются функции семейства unwrap(). Например, я точно знаю, что библиотека разбора аргументов командной строки не пропустит пустого значения для параметра SRC_FILE, и могу смело писать:

let path = matches.value_of("SRC_FILE").unwrap();

Смело потому, что попытка unwrap() для None обернется паникой и аварийным завершением приложения. Но для работы с такими ситуациями есть не менее удобный unwrap_or()

let std = matches.value_of("STD_VER").unwrap_or("11");

Среди относительно новых изменений языка числится `?`-синтаксис, которым я так и не решился воспользоваться, так как, на мой взгляд, он делает код просто невероятно сложно поддерживаемым и является злом по определению. Лучше уж отдать предпочтение макросу try!(), который делает то же самое, но более очевидным путем, а еще лучше либо явно звать unwrap(), либо писать полную обработку на базе match.

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

В то же время мне сильно не нравится количество смысловой нагрузки на одну линию кода. Даже в простейшем примере выше с unwrap_or() видно, что тут упаковано и создание переменной с присвоением ей результат вызова функции, и условная проверка с возвратом значения по умолчанию, если функция ничего не вернула. Многовато для одной строки далеко не самого сложного кода на Rust.

Кому может быть интересен

В интернете можно найти довольно много мнений и споров на тему того, является ли Rust “убийцей C++” или нет. Смешные дискуссии, особенно с учетом того, сколько своих “убийц” C++ пережил. Поэтому я не буду говорить о том, кого же Rust вытеснит, только время рассудит, но вот кому и когда он может пригодиться, уже более интересно.

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

По моим ощущениям, при помощи современного Rust проблемы могут быть решены как минимум не хуже, чем при помощи современного C++, и более качественно, чем на современном Go. Так, для C++ программиста, активно использующего C++11 с STL и BOOST в повседневной работе, Rust может показаться ограниченным языком, особенно за счет куда как более бедной системы метапрограммирования и особенностей обработки ошибок. В то же время, для разработчика, активно использующего C++ с Qt или тот же Go, всё должно быть наоборот, приятно и комфортно. Если говорить про порог входа, то, с одной стороны, он однозначно выше, чем в случае с Go, начать писать на котором можно через 3-4 дня активного изучения документации и лучших практик. С другой стороны, информация, с которой придется ознакомиться, куда менее объемная и запутанная, чем даже минимальное вводное чтиво по C++.

Для себя я сделал вывод, что буду и дальше использовать Rust в “домашних проектах” и, при возможности, протолкну его продуктовую разработку в команде. Жизнь будет проще, жизнь будет веселее!