
Краткое содержание
Мы рады представить две новые важные функции в Manticore Search: нечёткий поиск и автокорректировка запросов (или "автодополнение"). Эти функции улучшают возможности поиска, предлагая более удобный для пользователя опыт.
Типизированный язык программирования
Краткое содержание
Мы рады представить две новые важные функции в Manticore Search: нечёткий поиск и автокорректировка запросов (или "автодополнение"). Эти функции улучшают возможности поиска, предлагая более удобный для пользователя опыт.
То, о чем я собираюсь рассказать в статье настолько тривиально, что любой, даже начинающий, разработчик уже это знает - я правда очень на это надеюсь. Тем не менее, приходящий на ревью код, показывает, что люди как делали, так и продолжают делать что-то подобное:
- bool LoadAnimation(str::string filename);
- void DrawLines(std::vector path);
- Matrix RotateObject(Matrix m, Angle angle);
- int DrawSprite(Sprite sprite);
Что общего у этих функций? Аргумент по значению. И каждый раз, когда вызывается подобный функционал в коде, создается копия входных данных в своем временном контексте и передается внутрь функции. И можно еще простить редко вызываемый код, вроде загрузки анимаций или понадеяться на компилятор, что сработают оптимизации и он уничтожит копирование данных, но как назло, чаще всего такой подход к разработке уничтожает только перформанс и фпсы.
Если десятью словами: неумением ставить корректные эксперименты и экстремально гипертрофированным ощущением собственной важности. Я не буду описывать конкретный случай, с которым я столкнулся, а опишу выдуманный случай с такими же чертами.
Предположим к вам обратился товарищ, который хочет чтобы вы дали ему контакты принимающих решения менеджеров и топ-алгоритмистов в условном Микрософте. Зачем? После обмена репликами, где он сначала сопротивляется, выясняется что он изобрел новый алгоритм сортировки. В качестве доказательства он показывает программу на питоне, которая, по его словам, сортирует 10 чисел быстрее чем сортировка по умолчанию на питоне.
Поскольку эта статья завершает цикл про SOLID с примерами, хотелось бы показать, как эти принципы позволяют создавать что-то большее. В этой статье создадим небольшой модуль, каркас (framework), для работы с аргументами командной строки.
Обработка аргументов командной строки, с одной стороны, один из простейших примеров, который используют для решения начинающие разработчики. С другой, существует множество решений которые не только не соответствуют принципам SOLID, но и построены таким образом, что внесение почти любого изменения требует значительной переработки кода.
Разработку модуля начнем с определения цели, очень тривиально, но правильно поставленная цель, значительно упрощает реализацию. Основной целью модуля будет создание инструмента удобного для пользователя. Легко добавлять, изменять значения аргументов, легко перебирать значения.
Опишем функционал модуля.
Разработка этой программы затрагивает множество разнообразных технологий для совместной работы, которые на первый взгляд невозможно соединить. Добавляют сложности взаимодействия между типами еще разные языки программирования и разные разработанные для них библиотеки, в каждой из которых разработан свой функционал. В данной статье рассмотрим способы перевода двух несвязных типов.
Или почему не нужно бояться того, что удобно работает. Узнаем, что по этому поводу пишет стандарт, потом заглянем в реализации std::array в libc++ и libstdc++, затем посмотрим на ассемблер некоторых операций с этими объектами. Завершим всё это дело, как и полагается, бенчмаркингом.
Методы расширений, рассуждения о том что это такое, зачем это нужно и как реализовать в C++ с примерами.
Всем привет! Сейчас за окном осенние деньки 2024 года. Вещает Пройдаков Евгений. Сейчас я руковожу группой разработки среды исполнения языка eXtraction and Processing в R&D департаменте Positive Technologies.
Доменно специфичный язык eXtraction and Processing является важной частью движка поведенческого анализа, используемого в таких продуктах Positive Technologies, как MaxPatrol SIEM и PT ISIM. Сегодня хотелось представить вашему вниманию выжимку нашего R&D процесса в экспериментах с WebAssembly.
Узнаем, что такое WebAssembly. Поймём, как его можно встроить в программный продукт. Коснёмся инструментов разработки и сред исполнения WebAssembly. А также в рамках одной статьи пройдём путь от постановки задачи до результатов по разработке среды исполнения для доменно специфичного языка программирования.
Кроме того, мы разберем некоторые проблемы, которые могут появиться у вас при попытке собрать и отладить большой С++ проект под WebAssembly. Материал может быть особенно полезен тем, кто хочет использовать WebAssembly за пределами веб‑браузера.
Более подробно про сам язык eXtraction and Processing можно почитать в прошлой статье цикла от моего коллеги Михаила Максимова.
Будем рады всем неравнодушным к теме разработки доменно специфичных языков, компиляторов, сред исполнения. Неважно, опытный вы разработчик, начинающий или только интересуетесь ей.
В мире программирования создание собственных библиотек — это не просто возможность пополнения своего портфолио или способ структурировать код, а настоящий акт творческого самовыражения (и иногда велосипедостроения). Каждый разработчик иногда использовал в нескольких своих проектах однообразный код, который приходилось каждый раз перемещать. Да и хотя бы как упаковать свои идеи и знания в удобный и доступный формат, которым можно будет поделиться с сообществом.
Если вы ловили себя на мысли: «А почему мне бы не создать свою полноценную библиотеку?», то я рекомендую прочитать вам мою статью.
Эту статью вы можете использовать как шпаргалку для создания проектов, и не только библиотек.
Некоторые из вас могут подумать что мы изобретаем велосипед. А я в ответ скажу — сможете ли вы прямо сейчас, без подсказок, только по памяти, нарисовать велосипед без ошибок?
Всем привет!
При помощи нейронной сети решил проблему классификации фигур на изображениях размера 7 на 7 пикселей. Задача решалась в рамках студенческой лабораторной работы. Статья приводится в качестве руководства для решения подобных академических задач.
На работе я переписываю запутанный C++ код на Rust.
Из‑за активного использования коллбеков (вздох), Rust иногда вызывает C++, а C++ иногда вызывает Rust. Все это благодаря тому, что оба языка предоставляют C API для функций, которые можно вызывать со стороны противоположного языка.
Это касается функций; но как быть с методами C++? Представляю вам небольшую хитрость, благодаря которой можно переписать, без головной боли, один метод C++ за раз. И, кстати, это работает независимо от языка, на который вы переписываете проект, это не обязательно должен быть Rust!
В прошлой статье мы написали вполне себе разумный оповещатель (notifier) для рассылки уведомлений подписчикам (subscribers). Он достаточно удобен, там нет ничего лишнего - всего 130 строчек кода. Моменты, важные для клиентов этого кода, продуманы. Как например, многопоточный вызов доставки оповещений с минимальными взаимными блокировками и возможность отписывать прямо из обработчика подписчика.
На этом бы и остановиться, но мы шагнём дальше, добавив немного шаблонной магии и сделав код "академичнее".
Инверсия зависимостей — это стратегия зависимости от интерфейсов или абстрактных функций и классов, а не от конкретных функций и классов. Проще говоря, когда компоненты нашей системы имеют зависимости, мы не хотим напрямую внедрять зависимость одного компонента в другой. Вместо этого мы должны использовать определенный уровень абстракции между ними.
Вот такое сложное определение. Где, «Проще говоря», только больше запутывает чем поясняет, хотя все передает верно. Этот принцип пожалуй самый сложный для объяснений, хотя его суть очевидна.
Начну пояснения с бытового примера. Для работы лампы освещение необходим провод, ну и электричество естественно. Логичным является, встроить эту лампу в светильник, который будет играть двойную роль, защитную и декоративную. Что делать, если лампа вышла из строя, очевидно снять плафон вывинтить лампу и вставить новую и так далее, но это стало возможно, когда мы применили принцип инверсии зависимости.
Конструкторы разделили светильник на части, в программировании они называются модулями. Каждую из этих частей снабдили интерфейсами. Для лампы сделали интерфейс — патрон. Для плафона интерфейс — держатели и так далее. Теперь есть возможность извлечь лампу и заменить ее на другую, если у этих ламп интерфейсы совместимые. А что если светильник не разборный. Нам придется его разрушить, или выкинуть и купить новый.
То же происходит и в программном обеспечении. Если мы в самом начале неправильно разделили на модули и не выполнили инверсию зависимостей, при малейших изменениях, нам придется переписывать большой участок кода, и это хорошо, если этот код мы писали сами. Разобраться проще.
Я профессионально программирую на Rust и, признаться, немного этот язык продвигаю. Поэтому можете себе представить глубину моего расстройства, когда моя младшая сестрёнка, почти не умеющая программировать, обратилась ко мне и попросила научить её C++. Я попытался её отговорить, сказав, что однажды она будет сидеть за отладкой ошибок сегментирования, вооружившись Valgrind и вспоминать этот наш разговор, размышляя, а где же она свернула не туда. Но она оказалась ещё упрямее меня и настаивала: хочу выучить язык программирования, которым действительно пользуются люди.
Я не притрагивался к C++ с тех пор, как ещё в старших классах разрабатывал игры на Cocos2D-X, но решил, что сохранившихся у меня туманных воспоминаний о «правиле трёх» (или сколько там было? Пять? Ноль?) и прочих подобных материях будет более чем достаточно, чтобы решить такую задачу. Оказалось, что и мне требуется кое-что подучить, но я с удовольствием узнал, что существует большая аудитория, с которой можно поделиться этими знаниями. Почти любую концепцию из C++ легко понять, если объяснить её в ключе «о, эта как та штука из Rust».
Притом, что C++ местами несимпатичен, этот язык по-своему красив. Я и так это знал, но, когда взялся заново учиться C++, мне стало только яснее: если Rust в какой-то степени и превосходит C++ (допустим, вы верите, что это так), то лишь потому, что сам Rust стоял на плечах такого гиганта как C++.
Так что мы потратили пару недель, проштудировав серию руководств по OpenGL от ютубера под ником TheCherno (кстати, сама серия отличная). Две недели спустя нам удалось на экране единственный статичный голубой квадратик. Я уже стал опасаться, а не начнёт ли моя сестра сомневаться, стоило ли таким образом изучать разработку игр и пытаться изобразить что-нибудь на C++. Так что тогда я решил, что следует отбросить руководства господина Черно и взяться за разработку игры всерьёз.
В прошлой статье, отбросив всё, что нам было известно из мира «кровавого энтерпрайз IT», и опустошив чашу, мы «написали на коленке» простейший оповещатель (notifier). Объект, вызывающий по цепочке заранее зарегистрировавшихся клиентов (подписчиков) при наступлении какого-то события.
Настало время сделать его чуть удобнее для пользователей — добавить поддержку аргументов и позволить отписываться от событий прямо из кода подписчика.
Небольшая статья по настройке серверной части для телеграм бота, на базе языка программирования С++ и библиотек TgBot и sqlite3.
За время долгой работы в IT непосредственно с кодом, подмечаю одну особенность, что писать приходится всё меньше (в последнее время практически не писать), а ревьювить всё больше. И всё чаще видны нагромождения тонн кода, которые по факту не нужны, не вносят никакой дополнительной пользы. Но создают раз за разом головную боль для следующего читающего этот код программиста, который вынужден что-то поправить или дописать в этом коде. По итогу, программист махает рукой на эту чудную "архитектуру"... и пишет ещё один wrapper / adapter над ним. И, таким образом, передаёт пламенный привет последующим коллегам в будущее ;).
Попробуем взять и переписать с минимумом кода одну из очень часто встречающихся задач - рассылку уведомлений объектам в коде при возникновении какого-то события. На первый взгляд кажется, что в c++ уже есть все инструменты, чтобы написать этот код в несколько строк: функтор std::function<...>
- чтобы сохранить отложенный вызов, контейнер std::vector<std::function...>
- чтобы сохранить цепочку отложенных вызовов. По которым нужно просто пробежаться при возникновении события и вызвать сохранённые функторы...
Привет, Хабр! Меня зовут Давид, еще недавно я был стажером YADRO, а сейчас работаю в отделе разработки ПО поддержки сетевой аппаратной части. У нас в команде есть большой проект на более 100 000 строк, написан на C++ (и частично на С). Код переписывался много раз, а за самим проектом на правах легаси особо никто не следил: работает — не трогай. Когда я пришел в команду, у меня была задача: привести код в порядок и отловить ошибки, которые пропускает компилятор — например, возможное разыменование нулевого указателя, неинициализированные переменные или простые опечатки.
Одним из очевидных решений было использование статического анализатора. Выбрали довольно известное коммерческое решение, но долгие прогоны не привели ни к чему дельному. Решили поэкспериментировать с другими вариантами статических анализаторов, сделав ставку на open source. Поиски привели к инфраструктуре CodeCheсker, которая предоставляет удобный интерфейс запуска и настройки статических анализаторов через аргументы командной строки. С помощью инструмента удалось достичь результатов, которые значительно превысили значения, полученные на коммерческом решении.
Под катом расскажу, что же такое CodeCheсker, как с ним работать и почему его точно стоит попробовать на большом проекте.
Принцип разделения интерфейсов предполагает, что вы не должны заставлять клиента реализовывать интерфейс, содержащий методы, которые ему не нужны. Вместо этого вам следует разбить более крупные интерфейсы на более мелкие, ориентированные на конкретные случаи использования.
Этот принцип пожалуй самый простой для понимания, но важный при реализации. С разделением интерфейсов мы встречаемся постоянно, правительство любой страны имеет интерфейсы, которые называются министерствами, компании - интерфейсы в виде отделов, материнская плата - интерфейсы для подключения памяти, процессоров и другой периферии. Тоже самое логично делать и в программировании.
В чем суть принципа разделения интерфейсов. Если перефразировать простыми словами, не нужно делать два дела сразу. Сознание человека так и построено, вспомните детскую задачку, когда просят одновременной дотянуться пальцем до кончика носа и гладить живот по часовой стрелке.
Прежде чем создавать свой пример, давайте рассмотрим пару участков кода из интернета. Из кода удалены приватные части классов, а так же конструкторы и параметры методов. Исключительно для экономии места.
Первый пример, выдержка из огромного класса интерфейса API, весь класс содержит около 30 методов и не представляет интереса, но показанный участок, иллюстрирует проблемы которые возникли у автора кода при модификации.
Читая исходный код Unreal Engine 5 я частенько стал натыкаться на загадочный макрос UE_TRACE_LOG (например, использование этого макроса можно заметить в коде UE_LOG). В этой статье я хотел бы рассказать, зачем нужен макрос UE_TRACE_LOG и как он связан с Unreal Insights.