Программирование vs. прочие сферы деятельности

  1. Программирование демократично (в отличие от, например, политики). В сообществе разработчиков нет выраженной иерархии. Нет «элиты», уровень которой недостижим для простых смертных. Общение с великими программистами доступно каждому — зайдите на любой популярный форум разработчиков и общайтесь, сколько влезет. Можете написать письмо Фаулеру или Степанову, и если письмо будет по существу, они скорее всего ответят.
  2. Программирование справедливо. Все знаменитые программисты стали таковыми исключительно заслуженно. Шарлатаны моментально обнаруживаются и посему практически отсутствуют (или окучивают дилетантов).
  3. Программирование доступно всем. За последние двадцать лет оно потеряло остатки своей элитарности, и теперь программистом себя называет каждый, кто написал «Hello, World» и знает несколько аббревиатур. Всем доступны среды разработки, компиляторы и вообще все необходимые инструменты для производства конечного продукта, в отличие от большинства «материальных» профессий (например, стеклодувов или специалистов по микроэлектронике).
  4. Программировать сложно. Для разработки качественной программы нужно знать кучу разных вещей, и научиться этому за пару лет невозможно. Я вырос и перестал верить в Деда Мороза и малолетних разработчиков-гениев (олимпиады не в счет, они бесконечно далеки от реальности). Оптимистичным сроком обучения с нуля до уровня середнячка я бы назвал 6–10 лет. Тем не менее, подавляющее большинство считающих себя программистами таковыми не являются и никогда не будут.
  5. Программирование требует наличия своеобразной манеры мышления. Об этом я уже писал.
  6. Пользователи обычно не могут адекватно оценить качество программы. Всякий может посмотреть на результат труда писателя или художника и составить свое мнение. Но по поводу программы максимум, что можно услышать, — удобная она или нет; насколько программа корректно проверяет входные данные, насколько аккуратно обращается с памятью, продумана ли безопасность — все это невидимо. Зато когда вдруг исчезает квартальный отчет, все шишки падают на прибежавшего на крик сисадмина.
УжасноПлохоНормальноХорошоОтлично (Еще не оценили)
Loading ... Loading ...

Философия considered harmful

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

Леонардо да Винчи

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


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

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

Природа ценностей и их роль в социально-гуманитарном познании.

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

Меня всегда поражал подход социально-гуманитарных «наук»: прицепиться к какому нибудь определению или явлению (часто не понимая его сути) и навертеть вокруг этого целую теорию. Да, я могу назвать главную ценность гуманитарных наук. Их главная ценность — убедительность. Не важно что, не важно о чем. Если тебе поверили — твоя цель достигнута. К несчастью, многие ученые-естественники не умеют или не хотят говорить настолько же часто, много, убедительно и доступно для обывателей. В результате мнение о науке складывается не по выступлениям ученых и научным публикациям, а по интерпретации этой науки тружениками пера.

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

Еще один пример — синергетика. Типа, теория самоорганизующихся систем. Да, название громкое. А начинаешь выяснять, чем занимается эта самая синергетика — выходит, что в общем-то ничем особенным. В основном, пытается оправдать собственное существование. Ну, типа физика с информатикой встретились, — бах! — новая наука. Фактически синергетика заключается в нескольких самоочевидных постулатах вроде такого:

Когда системы объединяются, целое не равно сумме частей.

Открытие века, блин! Каждый ребенок совершает такое открытие, собирая машинки из Лего. Куча запчастей сама по себе никуда не поедет, очевидно же. Синергетики это тоже в конце концов поняли, и решили еще заняться неравновесными состояниями. Вывели еще парочку постулатов:

Неравновесность в системе является источником появления новой организации (порядка).

В сильно неравновесных условиях системы начинают воспринимать те факторы, которые они бы не восприняли в более равновесном состоянии.

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

И ведь десятки тысяч людей что-то делают, пишут какие-то работы, получают деньги… Безо всякого полезного эффекта. И не только в синергетике, которая является международным помешательством. У нас хватает своих российских тараканов: торсионные поля, наношампуни «с экстрактами бриллиантов», разнообразные артефакты Петрика и прочая псевдонаука. Миллионы человеко-лет тратятся впустую. Так вот, философия сейчас — примерно такая же псевдонаука.

Всех аспирантов РАН заставляют приобретать книгу «Философия науки. Общие проблемы» Степина.  Объемом около 400 стр. Стоит она около 500 р. Автор книги, разумеется, сотрудник института философии РАН, где я и проходил обучение по оному курсу. Я такую тоже купил, куда деваться. Открываю, — а там первая глава «Предмет философии науки». Отлично, думаю, сейчас я наконец узнаю, чем же философия науки занимается. Глава занимает 7 страниц примерно такого текста:

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

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

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

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

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

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

И чему должна научить такая книга будущих ученых? Писать много и запутанно? Скрывать лживые утверждения за малопонятными выражениями? В реальности, похоже, цель этой книги — содрать 500 р. с каждого аспиранта. Пять старушек — рубль. Достойная цель для философа!

Впрочем, положительные впечатления от курса философии все же были. Первое — отличная лекция о математической аксиоматике, непонятно как попавшая в курс. Второе — семинары. Семинарская группа была маленькая и отбирали в нее исключительно математиков, физиков и CSов. Атмосфера соответствовала. Мы пили чай и читали друг перед другом доклады. Обсуждение любого доклада, скажем, о схоластическом образовании, довольно быстро сходилось к спорам по поводу постройки БАКа, обучения нейронных сетей или квантовой физики. Все попытки семинаристки вернуть нас в философское русло были обречены на провал — у нас была своя философия. Ее красноречие разбивалось о нашу логику. В конце концов, она осознала нашу безнадежность и свое бессилие.

На кандидатском экзамене все получили высший балл: семинары научили нас сводить любой вопрос к своей области науки. У экзаменаторов просто не было шансов.

После экзамена на меня внезапно снизошло просветление, и я постиг Главный Принцип Педагогики: «Чтобы хорошо делать X, нужно делать X. Разговоры об X такого эффекта не дают». Из этого Принципа я сразу же вывел следствие под номером один: «Чтобы человек стал ученым, нужно, чтобы он занимался наукой. Чтение книг по истории и философии науки ему не поможет».


Добавлено

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

УжасноПлохоНормальноХорошоОтлично (4 голосов, средний: 5,00 из 5)
Loading ... Loading ...

Научный юмор

Утащил не помню где.


Бесконечное число математиков заходит в бар.
Первый заказывает полкружки пива, второй — четверть кружки, третий — одну восьмую…
Бармен:
— А-а-а… Не парьте мне мозг! Вот вам кружка пива!


Как физик доказывает, что все нечетные числа простые:
1 — простое,
3 — простое,
5 — простое,
7 — просое,
9 — ошибка эксперимента,
11 — простое,
13 — простое,
15 — ошибка эксперимента,
17 — простое,
19 — простое.
Доказано!

УжасноПлохоНормальноХорошоОтлично (5 голосов, средний: 5,00 из 5)
Loading ... Loading ...

Если XOrg падает при запуске Qt-приложений

А именно, XOrg 1.9 и несколько мониторов, сконфигурированные с помощью Xinerama, приводят к стабильному падению Qt- и некоторых Tk-приложений. Это подтвержденный баг. К сожалению, часто в репозиториях популярных дистрибутивов нужные фиксы появляются очень неторопливо, а жить с таким багом ну никак невозможно.

Исправляется баг элементарно: нужно накатить соответствующий патч на исходники иксов и пересобрать. Для арчеводов на форуме приведена подробная инструкция (подразумевает использование Arch Build System).

Обратите внимание на феерический комментарий к патчу:

This fixes a typo introduced in commit 80b5d3a3264d2c5167e5ac85a3b04af0f89cece1. The pointer pDst was changed unintentionally to pWin from a copy/paste error. This resulted in all QT-based apps and some tcl/tk ones (like fontforge) to crash X 1.9 on starting up, when Xinerama was enabled.

То есть, некто внес в код XOrg критическую ошибку в результате бездумного применения copy/paste. Для проекта такого уровня — эпический фэйл.

Boost Program Options: разбор командной строки в стиле ООП

Определения

Рассмотрим команду:

prog -ab -n 10 --style=awesome file1 file2

Здесь:

  • prog — имя программы;
  • a, b, n, style — опции;
  • style — длинная опция;
  • -ab — сгруппированные опции;
  • 10 и awesome — аргументы опций;
  • file1 и file2 — параметры.

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

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

Возможно, вы видели и другие варианты названий, неважно — я буду пользоваться этими.

Требования

Мы хотим от парсера командной строки поддержки следующего:

  • коротких (-f) и длинных (--input-file) опций;
  • опций с аргументами и без;
  • опций с обязательными и необязательными аргументами;
  • возможности задания значения аргумента по умолчанию и/или неявного значения аргумента;
  • распознавания сгруппированных опций: -abc должно быть эквивалентно -a -b -c;
  • взаимоисключающих опций;
  • параметров;
  • распознавания лексемы «--», разделяющей опции и параметры;
  • возможности выполнить произвольную функцию, если задана некоторая опция;
  • строгой типизации аргументов опций;
  • автоматического формирования справки по опциям.

Также мы хотим, чтобы парсер уведомлял о

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

Реализация

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include <iostream>
#include <vector>
#include <string>
#include <iterator>
#include <boost/program_options.hpp>
namespace po = boost::program_options; // чтобы было короче
using namespace std;
 
// Вспомогательная функция - выводит содержимое вектора строк.
void print_vector(const vector<string> &v, const string &name)
{
    cout << name << ": ";
    for (vector<string>::const_iterator i = v.begin(); i != v.end(); ++i)
        cout << *i << "/";
    cout << "\n";
}
 
// Функция уведомления, автоматически вызываемая при задании опции -v.
// В аргументе функции передается аргумент опции.
void value_notifier(int v)
{
    cout << "Value notifier, argument is " << v << "\n";
}
 
int main(int argc, char *argv[])
{
    // Группа опций под названием "Visible". Эти опции будем включать в справку.
    po::options_description desc_visible("Visible options");
    // Добавляем опции в группу. Обратите внимание на удобный синтаксис. Функция add_options()
    // возвращает объект-функтор, создающий объекты опций.
    desc_visible.add_options()
        // Обычная опция без аргумента. Длинное и короткое имя указываются через запятую.
        ("help,h", "produce help message")
 
        // Опция с обязательным аргументом типа int. При указании опции в командной строке
        // вызывается функция value_notifier(), которой передается значение аргумента.
        ("value,v", po::value<int>()->notifier(value_notifier), "A value. Argument is mandatory.")
 
        // Опция-флаг. С ней автоматически связывается аргумент булевского типа, который
        // равен true, если опция указана в командной строке, и false в противном случае.
        ("aflag,a", po::bool_switch(), "Flag A")
 
        // Полностью эквивалентно предыдущей записи, но выражено более многословно.
        // zero_tokens() не дает задать аргумент опции, default_value() задает значение аргумента
        // по умолчанию (когда опция не задана), а implicit_value() задает неявное значение аргумента
        // (когда опция задана без аргумента).
        ("bflag,b", po::value<bool>()->zero_tokens()->default_value(false)->implicit_value(true), "Flag B")
 
        // Для закрепления: если опция указана, у нее может быть целый аргумент. Если аргумент
        // опции не указан, считается, что он равен 10. Вызов implicit_value() делает указание
        // аргумента необязательным.
        ("implicit,i", po::value<int>()->implicit_value(10), "Implicit value option")
 
        // Задание опции, аргументом которой является список. Такое нечасто встретишь.
        // Функция multitoken() позволяет комбинировать аргументы несколько раз заданной опции.
        // zero_tokens() позволяет задать список нулевой длины. Тип аргумента vector<string> позволяет
        // включать в значение аргумента несколько следующих за именем опции лексем, не
        // являющихся именем опции.
        // Опция может быть задана так:
        // 1. --list // пустой список
        // 2. --list a b c // список содержит a, b, c
        // 3. --list a -i 10 --list b c // список содержит a, b, c
        ("list", po::value< vector<string> >()->multitoken()->zero_tokens(), "list of some values");
 
    // Группа опций, которую мы не будем показывать пользователю. Зачем эта группа, описано ниже.
    po::options_description desc_hidden("Hidden options");
    desc_hidden.add_options()
        // Опция с аргументом-списком. Обратите внимание на задание значения по умолчанию. Если
        // для типа значения аргумента не определен оператор << для ostream, должно быть явно задано
        // текстовое представление указываемого значения (в данном случае - пустого вектора).
        ("pos2",
         po::value< vector<string> >()->default_value(vector<string>(), ""),
         "First two positional arguments")
 
        // Такая же опция.
        ("posrem",
         po::value< vector<string> >()->default_value(vector<string>(), ""),
         "Remaining positional arguments");
 
    // Группа опций, объединяющая две ранее определенные группы.
    po::options_description desc;
    desc.add(desc_visible).add(desc_hidden);
 
    // Описание параметров ("позиционных опций"). Теперь внимание. В значение аргумента опции
    // pos2 попадают первые два параметра, остальные параметры попадают в значение аргумента
    // опции posrem (на это указывает -1).
    po::positional_options_description p;
    p.add("pos2", 2).add("posrem", -1);
 
    // Здесь будет сохранен результат разбора.
    po::variables_map vm;
    try {
        // Предписываем использовать desc как множество распознаваемых опций и p как
        // множество "псевдоопций", предназначенных для "усыновления" параметров.
        po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
        // Вызвать функции уведомления (value_notifier() в данном случае).
        po::notify(vm);
    }
    // Обработаем исключения, генерируемые при некорректном синтаксисе.
    catch (const po::invalid_command_line_syntax &inv_syntax) {
        switch (inv_syntax.kind()) {
        case po::invalid_syntax::missing_parameter:
            cout << "Missing argument for option '" << inv_syntax.tokens() << "'.\n";
            break;
        default:
            cout << "Syntax error, kind " << int(inv_syntax.kind()) << "\n";
            break;
        };
        return 1;
    }
    // Обработаем исключение, генерируемое при обнаружении неизвестной опции. Есть еще
    // несколько типов исключений, но в подавляющем большинстве случаев нужны только эти.
    catch (const po::unknown_option &unkn_opt) {
        cout << "Unknown option '" << unkn_opt.get_option_name() << "'\n";
        return 1;
    }
 
    // Задана опция help - выводим справку по опциям группы "Visible". Справка по опциям pos2 и
    // posrem не выводится (зачем пользователю знать, как мы обрабатываем параметры?).
    if (vm.count("help")) {
        cout << desc_visible << "\n";
        return 1;
    }
 
    // Примеры типизации значения аргумента.
    if (vm["aflag"].as<bool>() == true)
        cout << "Flag A is set\n";
    if (vm["bflag"].as<bool>() == true)
        cout << "Flag B is set\n";
 
    // Типизация векторов.
    if (vm.count("list")) {
        print_vector(vm["list"].as< vector<string> >(), "List");
    }
 
    // Здесь не надо проверять vm.count, как у list, потому что мы задали значения по умолчанию.
    print_vector(vm["pos2"].as< vector<string> >(), "pos2");
    print_vector(vm["posrem"].as< vector<string> >(), "posrem");
 
    return 0;
}

При сборке нужно подключить библиотеку libboost_program_options.

Чего мне не хватает в Program Options:

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

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

Также обязан заметить, что я представлял в качестве читателя человека, для которого синтаксис C++ не является сюрпризом.

УжасноПлохоНормальноХорошоОтлично (4 голосов, средний: 5,00 из 5)
Loading ... Loading ...

Немного рефлексии

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

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

Самым простым выходом было бы просто не заплатить в очередной раз за домен — и все дела. В самом деле, что мне такого особенного дает блог? Тренировка писательских навыков? Этого у меня и на работе, и в аспирантуре предостаточно. Сохранение сведений на будущее? Для этого у меня есть своя Wiki, записи в которой отличаются сверхлаконичностью и, к тому же, обычно написаны на английском (так короче). К публикации всяких незначительных событий собственной жизни я отношусь скептически. Вот и выходит, что остается единственный мотивирующий фактор — сознание того, что мои посты могут кому-то оказаться полезными или хотя бы интересными.

Вам интересно? Вам пригодилось что-нибудь? Хотите, чтобы я о чем-то написал подробнее? Напишите коммент — вам несложно, а меня смотивирует на новые посты.

P.S. Завтра будет пост про Boost Program Options.

P.P.S. Посты про make & Autotools таки тоже будут. Про Python не будет, забросил пока.