bash.im ithappens.me zadolba.li

Программизмы

12372

Наступая на свежие грабли

К сожалению, часто тот, кто не желает учить ряды Фурье, абсолютно прав. Если вы программист, посмотрите на свою работу со стороны: многим ли из вас понадобилось всё это?

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

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

Мне могут возразить про новые решения взамен устаревших — возможно, так, но помните: «устаревшие» писали, возможно, ещё для процессора 80286, 25 МГц, 512 КБ RAM, экономя каждый такт и байт, а вы щедро разбрасываетесь гигабайтами и гигагерцами. Итог предсказуем: огромный неповоротливый монстр из кривых и сырых библиотек классов, худо-бедно ворочающийся на суперновой девелоперской тачке, но виснущий у пользователей.

Слово RFC вообще многие видят впервые. Некоторые, правда, что-то слышали про ITIL: так вот, те RFC — это другие RFC. Правильно, зачем нам читать унылый формальный документ на английском, когда можно на форуме поискать тему «как работает сервер ХХХХХ?» Ну, несколько ключевых команд не реализовали, ну, некоторые стандартные «расширили», ну, потом пользователи плюются — так это потому, что пусть нашу программу используют, а не какую-то там!

Общего представления об интернет-протоколах они могут вообще не иметь: считают, что HTTP отличается от SSH только номером порта, например. Не знают, что доменное имя www.site.ru совсем не обязательно означает веб-сайт на сервере site.ru и совсем не обязательно на российском.

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

Что же — есть те, кому оно нужно сразу. Но было бы куда полезнее сначала научиться программировать, а потом уже при необходимости лезть в математику, будь то системы помехоустойчивого кодирования, статистический анализ или матрицы с рядами. Просто помните: программирование — это поиск оптимального решения задачи. Вы должны понять её и найти способ реализовать. Если для этого нужна «вышка» — значит, она понадобится. Если не нужна — не стоит тратить силы, всё равно забудете и придётся учиться заново.

Вот если бы это ещё наша система образования поняла…

12366

Фурье (не путать с фурри)

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

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

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

— Да ну вот, на вычмате мы матрицы раскладываем… (Минута жалоб.) И на кой оно мне?..

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

12340

Жемчужина в куче фейспалмов

Жить или нет в чумном бараке — каждый решает для себя. Это не какое-то свойство конкретной профессии, а скорее свойство возраста. И для меня в IT всё ровно наоборот.

Во-первых, IT — это одна из немногих сфер, где ты можешь быть уверен в своём профессионализме. После освоения основного объёма информации по какой-то теме достаточно изредка читать новости и апдейты, чтобы сохранять навык. Зачастую знания, полученные 20 лет назад, оказываются актуальными и поныне (или, как минимум, сильно облегчают освоение темы).

Во-вторых, IT — это чуть ли не единственная сфера, где почти всё можно попробовать и проверить, прежде чем пускать в ход. Это не хирургия, где пациент реально может оказаться трупом. Да что там, даже у водителя автобуса больше риска, потому что он не может посреди движения отвлечься, а в случае ошибки — откатить автобус на пять минут назад.

В-третьих, устаревание в IT сильно преувеличено. Что принципиально изменилось в структурах баз данных за десяток лет? Какие радикально новые и шокирующие принципы, отменяющие все предыдущие знания, появились в ООП? Ну, поменялась за год радикально пара-тройка библиотек, появился какой-нибудь новый язык сомнительной полезности и унылый фреймворк. Может быть, вышла новая версия актуального для работы языка (хотя это случается раз в пять-семь лет). Тоже мне, трагедия…

В-четвёртых, ни 13-летний, ни даже 23-летний никогда не сравнятся с разработчиком с 20-летним стажем. И совершенно плевать, что они могут знать больше о чём-то новом: получить технические знания нетрудно, а вот опыт дебаггинга и разработки, особенно командной, развивается годами. Тут как у любых инженеров: «Опыт прямо пропорционален количеству испорченного оборудования».

В-пятых, приемлемое образование в IT действительно сложно получить… в России. Но я видел учебные программы и их результат в других странах. Они превосходны и реально могут сэкономить много времени при прокачке опыта.

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

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

Удачи!

12284

Пять лет байторубки строгого режима

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

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

Для этого придётся отказываться от мешающих факторов. Сторонники линуксовой консоли предложат отказаться от GUI. Сторонники «Менуэтов» и «Колибри» — от ЯВУ. Вначале эти концепции будут работать по отдельности. Затем требования к производительности возрастут настолько, что придётся отказаться от того и другого одновременно. Потом — вернуться от алфавитно-цифрового ввода-вывода информации к чисто цифровому. И, наконец, от чисто цифрового перейти к тумблерно-светодиодному, как в MITS Altair и микротренажёре МТ1804.

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

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

12239

Сингулярность своими руками

Создавая собственный мод к игре X²: The Threat, я задумывался над тем, что изюминкой моей модификации должны стать не только графические изыски, дотягивающие игру 2000 года до уровня почти современной графики, или, к примеру, скрипты, создающие уникальные события или миссии для игрока. Хотелось внести в игру ещё и какой-нибудь совсем уж нереальный элемент вроде черной дыры.

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

Графически планета должна выглядеть соответственно общим представлениям о прожорливом брюшке вселенной. Нарисовал в 3ds max модель — вернее, составил её из уже имеющихся в игре стандартных элементов, несколько модифицировав их размеры и список текстур. Получил вполне смачную сингулярность с тёмным ядром, аккреционным диском из пыли и падающими к ядру облаками газа. Удовлетворившись визуальным результатом, решил сразу поэкспериментировать, как это будет смотреться в игре.

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

Я никогда не декомпилировал ядра игр. А это возможно, и многие это делают — честь им и хвала! Мои же модификации всегда опираются больше на возможности простой подстановки или скриптового программирования.

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

Вот здесь я, собственно, и споткнулся. Забыл, что, в отличие от всех прочих объектов вселенной Х², помещаемых в игру по цепочке «INI-файл — сцена — модели в сцене», планеты помещаются иначе: INI-файл ссылается на головную модель самой планеты, к которой привязывается сцена, состоящая из нескольких слоёв: модели с текстурой ночных городов, полусферы тумана и ночного затенения, слоя облаков, слоя свечения атмосферы.

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

Игра благополучно запустилась, проглотив изменения.

Наученный опытом прошлых внедрений в игру всяческих объектов, я не стал устанавливать сингулярность в секторе присутствия. Для начала читерским скриптом открыл для пользователя всю карту вселенной, а затем, написав новый скрипт в одну строку, внёс объект «чёрная дыра» в соседний сектор.

Неладное я заподозревал в момент создания объекта. Резкие броски корабля по крену и дифференту были обусловлены не то торможением программы, пропихивающей сбойный объект в математику ядра, не то заранее заданными создателями эффектами. Но через несколько секунд всё успокоилось. Забыв о том, что можно в другом секторе просто создать корабль или станцию игрока и за счёт внешнего контроля за собственностью осмотреть окружающее пространство, я решил сунуться туда сам. Разогнался, прошёл врата… Грандиозный «бабах» был ответом на мои изыски.

То, что клюкнула сцена, понятно. Но почему ядро игры вместо красивой сияющей сингулярности поставило по координатам просто чёрный шар, а заодно разнесло все рукотворные объекты сектора, для меня пока загадка. Однако, когда та же самая математическая сила разнесла в щепу и мой кораблик, а игра, продолжая правильно отрабатывать, вывела на экран надпись «The End» и корректно завершила работу, я вдруг вспомнил Оппенгеймера:

— Какая интересная физика!

12161

Раз-раз, как слышно?

Требовалось однажды создать двумерный логический массив 8×8. Памяти было очень мало, экономить приходилось на всём. А bool в C (да и почти везде) занимает непростительно много — целый байт. На весь массив, таким образом, ушла бы восьмая килобайта, а их было всего два. При этом от нас требовалась переносимость — просто взять несколько int для этой цели не удалось бы, так как мы не знали точного количества байтов в int на каждой конкретной платформе.

Задача решилась просто: мы взяли символьный массив из восьми элементов (char занимает один байт ровно на всех платформах) и использовали его как двумерный булеановский.

Это присказка, а не сказка. В одном ветвлении программы, которое становилось возможным с трёх дней постоянной работы (времени на тестирование было недостаточно, чтобы заметить это) закралось две ошибки. Первая — банальное падение программы. Вторая — забытое преобразование из char в int элементов массива при записи в лог. Когда программа упала, местный айтишник посмотрел в лог… Ну надо же было массиву принять значение {1, 1, x, y, u, -, \}!

12146

Типа того

В тридевятом царстве, в тридесятом государстве жили-были, не тужили, по-английски говорили Кен Томпсон и Деннис Ритчи. Но наскучила им басурманская речь, и придумали они новый язык. Да так ловко, что целые армии программистов по белу свету восприняли язык, как родной. Появились и проповедники языка С, и его адепты, и даже отдельные секты со своими священными сводами законов и правил, аки секта поклонников С++ во главе с Бьёрном Страуструпом. Но в основе своей все они жили по одному канону, установленному основоположниками языка.

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

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

И да, неявное преобразование типов в С/С++, к которому надо относиться очень внимательно — страшная вещь, особенно когда пишутся кроссплатформенные приложения. Не зря в одной толстой священной книге от Страуструпа этому вопросу отведена чуть ли не целая глава.

12139

А не дурак ли я?

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

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

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

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

Незнание об автоматическом приведении типов в используемом языке (скорее всего, C). Функция det() может возвращать значение не double, а более ёмкого типа, который компилятор приводит в double при присвоении в double и, наоборот, до которого расширит double при сравнении. С учётом этого факта никаких странностей в приведённом коде нет вообще — всё вполне логично. Перед тем как кидаться с обвинениями в адрес разработчиков компилятора, стоило открыть определение функции det() и посмотреть на тип результата, потом внимательно почитать описание стандарта языка программирования и сравнить реализацию на соответствие; наконец, почитать описание компилятора на тему особенностей реализации на той или иной аппаратной платформе и возможных отклонений от стандартов.

Морали в этой истории две.

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

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

12133

С оглядкой на хвост

Вздумалось кому-то (не мне) проверять, что матрица между вычислениями не поменялась. Проверять решил просто: считал определитель, сохранял значение и в нужный для проверки момент вычислял определитель опять. Если определитель не изменился, то можно спать спокойно.

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

В результате отладки дохожу до такого кода:

double a = det(M);
assert(a == det(M));

Ассерт срабатывает. Ладно, добавляю строчку:

assert(det(M) == det(M));

Ассерт не срабатывает. Функция всегда возвращает одно и то же значение. Добавляю:

double diff = a - det(M);

Результат равен нулю. Причём строго нулю, посмотрел побайтово. Та-ак… Похоже, что имеем вещественное число, в общем случае не равное самому себе. Уже интересно…

double a = det(M);
double b = det(M);
assert(a == b);

Ассерт не срабатывает. Пора в дурку…

Ларчик открывался просто. В сопроцессоре все числа обрабатываются в 10-байтовом формате, а double, как известно, 8 байт. Разработчики самого безглючного компилятора возвращали значение в голове стека сопроцессора и забыли нормализовать его до 8 байт. Нормализация происходила только в случае сохранения значения в переменной. Хвост в 2 байта добавлял несколько знаков к мантиссе и вызывал все эти спецэффекты.