Так себе программист
97 subscribers
184 photos
7 videos
1 file
183 links
Меня зовут Александр Троценко. Разработчик, преподаватель, к.т.н. Пишу о программировании и профессии.

10 лет в разработке desktop на C/С++

Контент: https://taplink.cc/atrotsenko
Download Telegram
Ошибки юмориста

“Опаньки…” Знакомо, да?
Рассмотрим типичные ситуации в сообщениях об ошибках, которые желательно избегать:
- непонятный пользователю технический жаргон (”фетчинг”, “токен”, “куки”);
- неуместный тон (”Упс! Что-то пошло не так”);
- перекладывание вины (”Сторонний сайт не отвечает на наши запросы”);
- общие фразы (”Попробуйте позже”).

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

Подробнее здесь и здесь.
👍1
Расширение импорта FreeCad

Составил небольшую инструкцию по созданию кастомного импортера в свободном САПР FreeCad. На удивление оказалось достаточно просто.
👍1
JavaScript в Python

Выполнение сценария JavaScript в Python возможно с использованием JS-движка QJSEngine. Это тот самый движок, на котором вертится Qml. Благодаря питоновской обертке над Qt - PySide, движок заводится не только в С++, но и в Python.

Поэтому если вдруг стоит задача расширить Python-программу каким-либо языком макросов, то связка с JavaScript выглядит как решение. Проверил, работает.
👍1
Табы против пробелов

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

Нууу... На самом деле сейчас это можно расценивать как вкусовщину. Да, с одной стороны использование пробелов обеспечивает одинаковую визуальную структуру кода во всех IDE и текстовых редакторах. С другой стороны, величину отступа по табу в любой IDE можно настроить (но не в любом редакторе) как тебе нравится. То есть, объективно говоря, как таковой проблемы здесь вообще нет.

Но автор статьи указывает один интересный момент. У него СДВГ. И с этой особенностью ему невероятно сложно различать отступы в размере двух пробелов. А еще, оказывается, есть брайлевские дисплеи и люди, использующие их, вынуждены читать большое количество пробельных символов в коде. Хотя при использовании табов символов было бы в 2, а то и в 4 раза меньше.

Казалось бы, такая очевидная вещь с такими неочевидными нюансами.
🤔3
Специальный САПР

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

САПР - системы автоматизированного проектирования.
👍1
Дайан Фосси

Дочитал недавно “Гориллы в тумане” за авторством Дайан Фосси, ученого-приматолога. Восхищен. Она посвятила 18 лет своей жизни изучению и сохранению вымирающего вида горных горилл в Центральной Африке (Руанда, Уганда, Конго). Работа была насыщенной: наблюдение за гориллами в естественной среде обитания, популяризация науки, воспитание нового поколения ученых, борьба с браконьерством.

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

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

26 декабря 1985 года Дайан Фосси была зарублена во сне в своей собственной хижине своим собственным мачете. Тайна убийства так и не была разгадана. Дайан была похоронена рядом с другими гориллами недалеко от хижины. Но ее дело продолжается, а горные гориллы стали национальным достоянием Руанды и надежно охраняются. Под влиянием Дайан популяция горных горилл увеличилась с 250 особей в 1981 году до более чем 2-х тысяч в 2020.

Кстати, есть одноименный художественный фильм “Гориллы в тумане”, где роль Дайан исполняет Сигурни Уивер. Фильм вышел буквально через несколько лет после смерти ученого.

#КнижнаяПолка
👍3
Аутентификация или авторизация

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

Authentication vs. Authorization
#Словарь
🔥2👌1
Мокинг или манки-патчинг

Вроде бы эти термины об одном и том же, но и тут нашлось над чем сломать голову.

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

Манки-патчинг (monkey patching) - это примерно то же самое, что и мокинг, только акцент смещается на подмену функциональности в рантайме. В случае с манки-патчингом речь может идти не только о юнит-тестах, но и о реальной логике. Это понятие особенно распространено в python, где подменить реализацию метода на ходу проще простого. Одной строкой объект получает другое поведение без создания каких-либо других объектов.

from SomeOtherProduct.SomeModule import SomeClass

def speak(self):
return "ook ook eee eee eee!"

SomeClass.speak = speak # Monkey patch

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

What is monkey patching?
#Словарь
👍2🤔1
Неэкспертное код-ревью

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

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

К тому же не нужно быть экспертом в предметной области, чтобы заметить ошибки в коде. Ревьювер выступает как интеллектуальный статический анализатор. Абсолютно все проблемы все равно никогда не найдёшь, но к этому пределу можно стремиться.
👍2❤1
Папка или директория

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

Директория - это концепт уровня файловой системы, а папка - концепт уровня пользователя. То есть в коде и в проектной документации выражаемся скорее как "директория", а в руководстве пользователя - как "папка".

Но глобально, на мой взгляд, понятия взаимозаменяемые.

#Словарь
👍3
Путаница в интерфейсах

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

1. Самый топ. Когда-то в ВК было два раздела: Сообщества и Сообщения. Ну невероятно близкие визуально написания. Так и хочется нажать не туда. Потом, конечно, Сообщения были переименованы в Мессенджер, но это не сразу помогло: я упорно продолжал искать Сообщения в Сообществах.

2. У Яндекса очень похожи значки приложений карт и музыки. Конечно не так, как Сообщения и Сообщества, но постоянно тыкаю не туда. Чтобы перестать путаться, пришлось разнести значки в разные папки. Им противопоказано находиться рядом.

3. Ещё замечал разного рода проблемы при выборе кнопки в диалоговом окне. Например, на вопрос “Cancel this operation?” предлагается два варианта ответа: “Ok” и “Cancel”. Что нажимать? Как программисту мне понятно, что Ok - это согласие, в Cancel - отклонение. Но семантически не так все очевидно.

На эту тему мне очень нравится утверждение “Less Similarity Breeds More Clarity”.
И за примером далеко ходить не нужно. Достаточно посмотреть на дорожные знаки.
👍5
Аргумент по ссылке, указателю или значению?

Небольшая памятка по передаче аргументов в функции С++.

1. По значению передаем в функцию базовые типы (int, double, float и т.п.) Я обычно ориентируюсь по размеру типа. Если размер типа 8 байт и меньше, то его можно передавать по значению, т.к. ссылка или указатель все равно “сожрут” свои 8 байт (x64) и выгоды при их использовании мы не получим.

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

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

4. Не константным указателем или ссылкой объявляем выходные аргументы. При этом иногда для улучшения читаемости кода в качестве выходных аргументов рекомендуют использовать именно указатель, а не ссылку.
👍6
Парсинг текста в boost/C++

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

В Gists я положил пример парсинга булевого значения из текста типа "option on" / "option off".
👍4
Изменить коммит

У git есть команда по изменению последнего локального коммита: git commit --ammend. Команда оказывается полезной, когда нужно исправить опечатку в сообщении коммита или добавить пропущенные файлы.

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

Тут как раз поможет commit --ammend. Лучше сделать коммит как есть, со всем мусором, и только после этого чистить код. Все исправления будут видны в git diff и в случае проблем можно будет сделать шаг назад. Когда все вычищено и проверено, просто дополняем последний коммит новыми правками.
👍2👌1
Условное логирование

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

В коде этот подход реализуется простыми условным конструкциями вроде такой:

if (IS_DEBUG_OSPF_EVENT)
zlog_debug ("setting options on %s accordingly", IF_NAME (oi));


Занимательно, что quagga по умолчанию включает именно отладочный (читай “многословный”) уровень логирования. Хотя количество записей в логах сильно не вырастает. Большая часть вывода спрятана под условиями.

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

#ЖизньДругих
Логирование в Qt/C++

На фоне предыдущего поста поковырялся в инструментах логирования фреймворка Qt. Из коробки логгер Qt писать в файл не умеет, но поведение можно переопределить через qInstallMessageHandler().
Как и log4cpp, Qt поддерживает категории логгера, для которых можно по-отдельности включать/отключать отладочный вывод через файл QtProject/qtlogging.ini.

Пример кода здесь.
👍3
Шаблоны задач

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

1. Баг (Bug). Собирает информацию о проблеме, ее воспроизведению и ожидаемому поведению.
2. Запрос фичи (Feature). Содержит предложение на реализацию новой функциональности.

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

3. Задача на знакомство с проектом (Onboarding).

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

Не устаю размышлять на тему сложности разработки ПО. Ну почему для разработки и начала выпуска пассажирского авиалайнера требуется 5 лет, а разработка программ может вестись десятилетиями? Вопрос занятный и я объясняю его себе так:

1. Разработка ПО - это постоянное проектирование. Фаза конструирования по отношению к проектированию не велика, а сборку и вовсе выполняет компьютер за считанные минуты. Авиалайнер же за обозначенные 5 лет скорее конструируют, чем проектируют. Многие компоненты уже давно спроектированы.

2. Низкая стандартизация продукции и процессов. Грубо говоря, любая прихоть клиента должна быть исполнена, иначе он не купит продукт. “В вашем авиалайнере нет доступа из салона в багаж? Ну тогда поищу тех, у кого есть…” Бред? Конечно бред. Но в разработке ПО “пришить третий рукав” - это обычное дело. Стандарта то нет.

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

4. Недостаточные компетенции разработчиков. Разработкой ПО могут заниматься специалисты с разным опытом. В то время как над авиалайнером работают сертифицированные инженеры. В ИТ сертификация специалистов пока только развивается.
👍4❤1
Пример работы с QtTest

Составил простейшую инструкцию по созданию юнит-тестов на QtTest в QtCreator.
Теперь есть с чего начать.
Ссылки на официальную документацию присутствуют.
🙏1
Преобразование size_t в int

Тема преобразования типов в C++ довольно обширная. В этот раз в статье затронули преобразование size_t в int. Проблема тут может быть одна - это переполнение типа. И приводит она к двум ситуациям:
- большое значение size_t преобразуется в некорректное маленькое значение int;
- большое значение size_t преобразуется в отрицательное значение int.

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

Для предупреждения проблем с преобразованием автор предлагает такое решение:

inline int SafeSizeToInt(size_t sizeValue)
{
constexpr int kIntMax = (std::numeric_limits<int>::max)();
if (sizeValue > static_cast<size_t>(kIntMax))
{
throw std::overflow_error("size_t value is too big to fit into an int.");
}
return static_cast<int>(sizeValue);
}


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

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

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

Алгоритм - это идея, представленная как конечная последовательность действий.

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

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

#Словарь
👍2