bash.im ithappens.me zadolba.li

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

11577

Проверка без пристрастий

Что ещё надо на олимпиадах, говорите?

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

11562

Ну что ещё?

Мне 17 лет. Недавно участвовал в школьном туре всероссийской олимпиады по программированию. В этом году впервые экспериментируют с полностью автоматизированным способом проверки работ (то есть живые проверяльщики вообще не привлекаются, вся ответственность ложится на могучие плечи серверов). Процесс проверки таков: кидаешь на сайт исходник, он там компилируется и кормится заготовленными входными данными (20 разных вариантов).

Вся олимпиада состоит из четырёх заданий. Пишу на C++. Всё решил, заливаю на сайт — ошибка: «Превышено время компиляции». Странно. Пробую отправить исходник, сохранённый в другой среде. «Превышено время компиляции». Решаю ради прикола попробовать прикрепить собранный бинарник (чушь, конечно, но просто уже не знал, что делать). «Превышено время компиляции», твою мать!

Когда наконец дошло, в чём тут дело, полусонные родители сбежались посмотреть, что случилось: я ржал, как полоумный. Оказалось вот что: я по привычке в конце каждого сорца наставил пустых приглашений на ввод (типа cin.get()). У бедного компилятора был ступор: что ещё от него хотят?

В итоге написал на 380 баллов из 400, долго радовался.

11521

В погоне за тактами

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

Изначально этот программатор разрабатывался как проект с открытым кодом и идеологией «максимальные возможности с как можно более простым для повторения аппаратным обеспечением». Следствием такого подхода стали использование порта LPT для подключения к PC, реализация устройства на микросхемах низкой степени интеграции (в основном регистры и инверторы). Вся логика управления была сосредоточена в софте. Как и случается с многими опенсорс-проектами, как только замаячила перспектива возможных доходов, всё стало потихоньку засекречиваться: сначала перестали выкладывать исходники софта, затем в софт добавили защиту от дизассемблирования и трассировки, а потом и аппаратное обеспечение для реализации подключения через USB переехало на микроконтроллер, прошивки для которого в открытом доступе не появлялись.

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

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

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

Так как оригинальный софт успешно писал микросхемы с похожим принципом записи, было понятно, что задача выполнима, а значит, предстоит оптимизация. Хоть мне и не хотелось использовать многопоточность в простой программе, но пришлось. Выигрыш по времени выполнения это дало небольшой, зато исчезло заклинивание GUI при выполнении длительных операций. Пришлось заняться оптимизацией процедур управления программатором. Самой затратной оказалась процедура передачи в программатор адреса. Необходимо было адрес очередной ячейки, выраженный 24-битным числом, делить на три части по восемь битов и побитно сдвигать в три линии передачи, сопровождая каждую посылку формированием строб-импульса. Сложность заключалась в том, что Delphi 7 позволял осуществлять операции битовой арифметики только над восьмибитными переменными, к тому же используемые линии вывода были подвязаны к битам регистра LPT-порта не по порядку.

Первоначальный вариант алгоритма формирования адреса тормозил из-за использования операций возведения в степень и округления (с его помощью удалось обойти часть ограничений на битовую арифметику). Первая пришедшая в голову идея: перенести часть кода в ASM-вставку и использовать для возведения двойки в нужную степень команду FPU FSCALE. Какой-то выигрыш это дало, но временной интервал в 200 мкс продолжал нарушался с завидной регулярностью. Когда до меня дошло, что во вставке мне никто не мешает использовать операции сдвига над DWORD, удалось полностью избавиться от операции возведения в степень, но выигрыш по времени всё равно был недостаточным. Более-менее приемлемый результат удалось получить после шести переписываний куска кода с нуля. К этому времени за пределами ASM-вставки остались только вызовы процедур формирования импульсов и временных задержек, полностью исчезли операции возведения в степень, сдвиг DWORD тоже оказался ненужным, везде, где можно, использовались предварительно рассчитанные константы. Количество ошибок, возникающих из-за нарушения предельного интервала, свелось к минимуму, что позволяло реализовать коррекцию неправильно записанных блоков при контрольном чтении. В принципе, на этом можно было бы и остановиться, так как программа уже позволяла решить поставленную задачу, но мне захотелось сделать всё красиво.

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

Первый же запуск обновлённой версии программы отправил WinXP в синий экран. Решив, что это была случайность, запустил программу снова. На этот раз результатом стал не только синий экран, но и сброс настроек BIOS. При пошаговой отладке выяснилось, что при первом вызове процедуры в функцию формирования импульсов передаются нормальные параметры, а при последующих вместо текущего адреса LPT-порта передаются абсолютно произвольные данные. Причина ошибки оказалась проста: желая освободить EBX для собственных нужд, я push’нул его содержимое в стек. При первом вызове процедуры формирования адреса указатель базы стека (который по умолчанию хранится в EBX) совершенно случайно оказался равен 378h, смещение на которое я и подсмотрел. При последующих вызовах база стека была уже другая, и вместо LPT-порта моя программа слала байты куда придётся.

После того как всё было отлажено и результат меня устроил (хотя полностью от процедуры контрольного чтения отказаться не удалось), я решил сравнить производительность своей и оригинальной софтины. Нашёл микросхему со схожим алгоритмом записи, но поддерживаемую оригинальной утилитой, и сравнил с помощью осциллографа временные интервалы формируемых сигналов. Результат ещё раз напомил мне о том, почему я перебежал из программистов в железячники: оригинальная софтина работала на 20–30 процентов быстрее моей. Могу лишь предположить, что вместо PerformanceCounter в оригинальной утилите используется какой-то ещё более точный таймер.

11510

Дебаг копипастой

Блок try/catch не даёт информации?

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

Я сделал обработку всех исключений в программе так, чтобы перед пользователем появлялось окно с кнопками «Продолжить работу» и «Отправить отчёт автору». В простом поле был текст из стека ошибки — полный, длинный, иногда на несколько страниц. Сверху написано: «Нажать на кнопку „Отправить отчёт автору“ и в теле письма нажать Ctrl+V». То есть нет встроенной отправки отчёта на почту, реализация самая простая, используется почтовый клиент системы (если он есть, конечно). А обработка вывода такого окна при любом исключении довольно проста.

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

Сделайте возможность обычному, неподготовленному пользователю просто передать сложную информацию. Вы значительно облегчите свой труд.

11508

Доверяй, не проверяй

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

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

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

Вопреки очевидному, я всё же попытался указать программисту на его ошибки. Я даже опустил вопрос, зачем вообще такая программа, которая ничем не помогает пользователю. Я задал другие. Как просмотреть, из чего состоит сумма прихода? Если вдруг ошибка, как её найти? Как сделать оборотку за больший период? Не достучался… Разработчик не видел проблемы в своём творении. А когда дальше встала задача сделать другой документ из этих же данных, он сделал ещё одну табличку под ручной ввод.

Правда, пользователи тоже были под стать программисту. Их всё устраивало. Даже не задали вопрос: «Какого чёрта мы дважды заносим одни и те же данные?» А чё, это же разные формы.

Это те самые пользователи, многие из которых уже лет десять упорно проверяют на калькуляторе, правильно ли компьютер посчитал в столбик, хотя я уже им во всех интонациях и со всеми типами эмоций говорил: «Компьютер при складывании в столбик не ошибётся, проверяйте те данные, что вы внесли». Те пользователи, которым не лень пересмотреть сотни, а то и тысячи строчек в поиске ошибки, но тяжело пользоваться одной кнопкой выборки, в которой будет не больше десяти строк.

Так что цепочка «„узкий“ преподаватель — „узкий“ программист — „узкий“ пользователь», похоже, живёт своей, непонятной нам жизнью. Достаточно трудно наладить связи с этим миром.

11506

Язык месяца — теперь с квадратными скобочками

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

Хочу искренне поблагодарить тех кто преподавал и преподаёт в моей альма-матер. Меня там учили не просто писать на C/C++ или Delphi. В первую очередь меня учили думать, «как программист», то есть логически. Нам ставили задачу, и проверяющим было всё равно, как она исполнена. Их волновало только то, правильно ли работает программа и насколько быстро выполняется. Каждую программу преподаватели тестировали и старались найти ошибки, чтобы мы их исправляли. И теперь, чтобы освоить другой язык программирования, я потрачу время только на изучение структуры и операторов. Никогда не мог понять «специалистов», хорошо пишущих на одном языке, при этом неспособных переключиться на другой. У меня возникает мысль, что не на ту специальность они пошли.

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

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

11504

О пользе диетического кода

В последнее время тут муссируется тема внедрения новых разработок, которые дюже охочи до системных ресурсов. Когда свежеустановленная Win8 после первой пачки обновлений грузилась минут пятнадцать, а потом сказала, что на 60-гиговом SSD (думал, под систему с антивирем хватит, остальное на другие диски) свободно всего 830 мегов, глаза у меня стали очень выразительные… Да, после отключения гибернации и свопа жить стало можно, но 37 гигов под голую ось?.. В общем, сговор софтовиков с железячниками на разорение народа для апгрейдов так и не отменили. Жаль.

Квартал назад принимал работу у старой закалки программера. Задачка была: на веб-фейсе (пока ещё не существующем) вывести данные о продажах и вкратце о происходящем по торговым точкам. Четыре профиля, каждый с одной кнопкой «Показать результат за выбранный промежуток времени», разница в колонках и их содержимом. Получил от программера 14 файлов общим весом 68 КБ, скормил Апачу. Теперь каждый (да, пусть только из Хрома, но это оговаривалось в ТЗ; мобильная версия учтена) может быстро окинуть взглядом происходящее за 30 секунд из любой… в общем, даже из того места, где со связью очень плохо. Крутится серверная часть на PIII-500/256/20. Пока тестировал, поднял на этой машине 3G-свисток со статикой. Народ стучался в него. Хватало, хотя машина стоит в серверной в центре здания.

— Господа, вы прямо сейчас хотите подняться из кресел и пойти в ближайший лес (там у Мегафона есть полумёртвая зона на 70 метров, связь никакая), дабы самостоятельно проверить отчёт?

Приятно удивило, что два высших чина компании восприняли мою фразу очень лояльно и минут через пять уже выходили из офиса, благо лес видно из окна. Кстати, хотели свой отчёт они достаточно внятно: каждая формочка-профиль была мне выдана и в распечатке со всеми подписями «утверждено», и в электронном виде с описанием полей. Вернулись через час с тестов, вручили мне вискаря за оперативность решения задачки, посулили бонус на окончание квартала и программеру $200 сверх оговорённого добавили.

Коллеги по айтишному цеху! Может, хватит питаться в «Макдональдсах»? Кефир и сельдерей — полезные и даже иногда вкусные.

11499

Масоны ни при чём

Миром правит не тайная ложа, а обычная лажа.

Большинство языков программирования возвращают лишь код последней ошибки ввода-вывода или же имеют блок try/catch, прерывающийся по первой же ошибке. Поэтому в catch стоит обработчик ошибок, который просто выводит ошибку по её коду. Если в блоке try открывается десяток файлов, то ошибка открытия одного из них ничем не будет отличаться от ошибки открытия другого. И чтобы точно определить название файла, нужно или плодить try/catch на каждое открытие, или заводить специальную переменную, в которой бы хранилось имя последнего файла, или сделать свою функцию открытия, которая будет отличаться подробной обработкой ошибок.

Но лень не побороть. Поэтому вот вам, дорогие пользователи, один try/catch на всю инициализацию и сообщение об ошибке, если какая-то ошибка произошла. А что — в 99,9% случаев всё и так отлично работает.

11494

Адмирал без флота, генерал без армии

Как ни крути, а работа в большом проекте имеет свои особенности, особенно когда дело заходит об анализе требований и их реализации. Сегодня нашёл вот такое послание от архитектора в коде (коммент к одному из полей в enum’е):

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