Истории с тегом: программизмы

Всего историй: 896

9603

С вас станется

Как-то раз попросили меня одногруппники помочь с заданием по Паскалю. Проходили циклы, задание было элементарное: вывести на экран числа от 1 до 10 в столбик.

— Только ты, это, давай так, чтобы поверил, что сами делали, не как в тот раз.

— Не вопрос!

WriteLn('1');

WriteLn('2');

WriteLn('3');

WriteLn('4');

WriteLn('5');

WriteLn('6');

WriteLn('7');

WriteLn('8');

WriteLn('9');

WriteLn('10');

9591

Программируем софтверные программы

Ищу работу. Каждая следующая контора всё смешнее предыдущей.

— Мы занимаемся разработкой программного обеспечения под заказ.

Так выглядит частый ответ на вопрос о действующих проектах и деятельности компании. Шикарно! А я думала, в булочную программистом устраиваюсь.

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

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

Неужели так сложно честно рассказать о зарплате? Почему надо уклоняться от ответа, долго мурыжить претендента тестовыми заданиями, несколькими собеседованиями? Скажите сразу, что 15 тысяч — ваш потолок. Я уйду сразу, не тратя своё и ваше время.

Зачем строить из себя ФСБ, ЦРУ и КГБ в одном лице? Что такого секретного в ваших проектах? Хотя бы в общих чертах можно рассказать суть и технологии? Я не шпион, я работу ищу. А вы строите из себя чёртовых Джеймсов Бондов. И это при том, что в вашу контору вообще может зайти любой — ни пропускного режима, ни замков на дверях нет.

Будьте честны с претендентами. Это упростит жизнь и им, и вам.

9579

Дитя ночи

Я вот уже три года пытаюсь бросить курить, но ничего не выходит. Но ночью-то организм не хочет курить, потому что спит!

Я таки нашёл тот самый кусок кода в своём сером веществе и синапсах, где стоит счётчик времени и инициализация переменных «день/ночь». Принудительно использовал везде «ночь» для всех классов, функций и объектов — вуаля, я теперь не курю!

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

9577

О нежности и бензопилах

Программировал я как-то мобильную игру — «захват флага». Несколько забавных эпизодов.

Потребовалось много итераций, чтобы отработать обыкновенный звук подбора бонуса. Я говорю: «Нежнее». Музыкант: «У меня тут и так стоит флейта». И вдруг меня осенило: «Поставь рояль». Банальный рояль, который стоит в MIDI-банках под номером 0. Сработало, в таком виде звук и вошёл в игру.

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

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

Была занятная ошибка: бот перепрыгивает через яму, потом падает в неё. Причина — «сено-солома»: где-то в коде я спутал «лево» и «право».

9574

WM_WHY?

В 1996 году мы с одногруппником, изучая Windows API, писали тестовые программы. Использовали предшественника C++ Builder — компилятор Borland C++ 5.0. И хотя компиляторы Borland всегда были очень шустры, на слабых машинах из-за огромного windows.h даже «Hello World!» собирался полминуты.

Мой одногруппник решил «оптимизировать» свою программу, заменив все макросы из windows.h на числовые значения: вместо WM_COMMAND в цикл сообщений вставил число 0111h, вместо WM_TIMER — 0113h, а вместо WM_CREATE — 0001h. Логика была простой: константы никогда не поменяются, значит, можно их и вбить, чтобы компилятор не трудился.

В результате программа стала совершенно нечитаемой, но скорость компиляции совершенно не возросла, ведь всё равно в программе нужно было оставить строку #include . Поэтому пришлось вернуть всё обратно. Конечно, мы догадались, зачем нужны эти «дурацкие» #define.

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

9567

Нелогично, но работает отлично

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

Надо рисовать на карте трассу спутника. Если верить формуле, трасса начинается на каком-то значении долготы, вырисовывает загогулины, причём иногда весьма интересные, и завершается на той же долготе плюс 360 градусов. Проблема состоит в том, что при рисовании надо ловить переходы через границу карты, завершать рисование справа и начинать рисовать трассу на карте слева. Сколько было визуальных глюков вокруг перехода через эту границу… Проблема исчезла, когда стали рисовать трассу три раза — со сдвигом −360, 0 и 360 градусов. Ненужное отсекалось само, нужные куски при рисовании стыковались сами. И не надо точки разрыва трассы искать.

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

9564

Голенькие одноклассники

Кодирую в PhpStorm. Пишу «NULL», промахиваюсь и печатаю «NU::».

Смотрю. Жму Ctrl+Space. Жду. Думаю, почему автокомплит IDE ничего не показывает. И что вообще за класс такой — «NU»?

Чувствую, что пора сделать перерыв на кофе.

9560

Жизнь, Вселенная, индусы и всё такое

Последних лет десять я занимаюсь SAP. Практически вся прикладная часть системы доступна разработчикам конечного пользователя в исходных кодах. Язык программирования ABAP/4, правда, несколько специфический. Говорят, похож на Кобол. Если сравнивать с популярными ныне языками, то у меня он более всего ассоциируется с Бейсиком.

Есть в ABAP два вида подпрограмм: формы и функции. Форма имеет локальную область видимости (хотя её можно вызвать извне, но тогда нужно указать имя главной программы, в которой размещён код формы). Функции имеют глобальную область видимости, но должны быть обязательно приписаны к какой-нибудь группе функций. SAP может поставляется в разной комплектации. Набор установленных компонент (и, соответственно, доступных групп функций) может отличаться. Из-за этого имя вызываемой функции передаётся как литерал и, если оно указано неправильно или в системе не установлен компонент, содержащий нужную группу функций, выяснится это только в процессе вызова. Разработчики различных модулей вынуждены делить между собой общее пространство имён функций, а также других объектов. Наверное, они как-то координируют имена всех создаваемых функций. Но, скажем так, у них с этим есть некоторые трудности, потому очень часто в разных модулях есть функции, выполняющие схожие действия, а имя функции содержит посторонние символы. К слову, у конечного пользователя тоже есть возможность разрабатывать свои функции. И чтобы хотя бы устранить проблемы с пересечением имён с объектами клиентов, SAP не создаёт свои объекты с именами, начинающимися на букву Z — такие имена зарезервированы для разработчиков конечного пользователя, а клиентам не рекомендует создавать объекты, начинающиеся не на букву Z.

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

Функция CBIH_RP02_GET_END_MONTH.

Через конструкцию CASE анализирует номер месяца. Для всех месяцев, кроме февраля, присваивает своей локальной переменной end_month1 соответствующее значение 30 или 31. Для февраля вызывает форму CHECK_DATE, передаёт ей дату и анализирует возвращаемую переменную L_ERROR. В зависимости от её значения устанавливает своей переменной end_month1 значение 28 или 29. Из исходного года и месяца и вычисленного дня формирует возвращаемую дату. Форма CHECK_DATE у переданной даты меняет число на 29, эта новая дата передаётся функции DATE_CHECK_PLAUSIBILITY, по возвращении из которой форма анализирует код возврата (была ли ошибка) и возвращает эту информацию в вызвавшую функцию. Функция DATE_CHECK_PLAUSIBILITY тщательно проверяет дату на корректность по григорианскому календарю (71 строчка исходного кода) и генерирует ошибку, если дата неправильная.

Функция FIMA_END_OF_MONTH_DETERMINE.

Ничего особенного — честно проверяет для февраля високосность года по григорианскому календарю. Впечатлило использование констант. Видимо, автору кто-то сказал, что хороший стиль программирования — никогда не использовать константы напрямую, а всегда их описывать в отдельно отведённом месте. Идея, конечно, здравая, но доведена до абсурда. Все необходимые группе функций константы описаны в отдельном инклюде FIMA_CONSTANTS (135 строк исходного кода). Я ещё понимаю описание констант для номера месяца типа CON_FEBRUARY(2) TYPE N VALUE '02'. Но это скорее исключение. Типичное описание:

CON_FIRST_DAY_OF_MONTH(2) TYPE N VALUE '01',

CON_DAYS_OF_MONTH_27(2) TYPE N VALUE '27',

CON_SBERFIMA_TLRA TYPE SBEWFIMA VALUE 'TLRA',

А код для присвоения числа, соответственно, такой:

CASE I_DATE+4(2).

WHEN CON_JANUARY. E_DAYS_OF_MONTH = CON_DAYS_OF_MONTH_31.

Функции, начинающиеся на «FKK».

Две из них, FKK_DTE_DAYS_PER_MONTH и FKK_DTE_GET_LASTDAY_OF_MONTH, находятся в одной группе FKDATE, причём рядом. В группе всего семь функций — трудно не заметить существующую тому, кто писал позже. Однако детали реализации отличаются — похоже, что каждой автор писал сам, хотя концептуально алгоритмы одинаковые. За исключением того, что вторая функция для дат до 1582 года вычисляет високосность года по юлианскому календарю. В обеих честно анализируются компоненты даты. Есть отличия в формате вызова.

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

Третья функция FKK_GET_LAST_DAY_OF_MONTH находится в группе FKB3A. Вычисляет последний день месяца с использованием встроенной операции над датами — прибавления и вычитания дней. Сначала она формирует дату на 28 число того же месяца и года, потом прибавляет к ней 4, получает дату заведомо в следующем месяце, устанавливает там день в «01» и вычитает единицу из всей даты. Простенько и со вкусом. Для дат в декабре 9999 года будет ошибка из-за переполнения года по ходу вычислений. Ну да кого это сейчас волнует?

Четвёртая функция FKK_LAST_DAY_OF_MONTH находится в третьей группе FKKPERIOD. Алгоритм компромиссный. Номер следующего месяца и года вычисляется «честно», потом формируется дата на первое число этого месяца и уже от неё отнимается единица. Функция корректно обрабатывает даты в декабре 9999 года, специально анализируя этот случай и возвращая константу «31.12.9999». Но при этом все даты до 1800 года считает некорректными и генерит на них исключения, как и на даты с неправильным месяцем. Если передана дата с неправильным днём, не замечает этого.

Функция HR_RU_DAQ_GET_DAYS_IN_MONTH.

Имеет 8 входных параметров, 2 выходных и 2 одновременно входных и выходных. При этом состоит всего из 58 строк кода (из них 26 выполняемых). Алгоритм вполне аскетичный, как у FKK_GET_LAST_DAY_OF_MONTH, только прибавляет не 4 к двадцать восьмому числу, а 31 к первому. Некоторые входные параметры помечены как необязательные и никак не участвуют в алгоритме. В некоторых функциях, не вошедших в этот краткий обзор, использовались вариации — например, к первому числу прибалялось 35 или 32. Видимо, 31 побоялись прибавлять — а вдруг не хватит? 32 и 35 — надёжнее. Или, может, они так округляли? Разницы-то действительно нет, сколько конкретно прибавлять, лишь бы попало куда-нибудь в следующий месяц.

Две замечательные функции END_OF_MONTH_DETERMINE и END_OF_MONTH_DETERMINE_2.

Находятся в группах FV03 и FV02 соответственно. При этом алгоритм практически повторяется. Видно, что вторая тупо списана с первой. Но автор второй, вероятно, решил не полагаться на автора первой, а иметь такую важную функцию под собственным контролем. Обе честно вычисляют високосность года, но только по юлианскому календарю. А чего заморачиваться — на ближайшие 90 лет-то хватит, а там пусть потомки решают «проблему 2100»…

Самая аккуратная реализация оказалась у разработчика конечного пользователя. Лаконичная, эффективная и снабжённая исчерпывающими комментариями. Это и понятно — он ведь заведомо не индус.

9554

Раз в год и палка стреляет

Лет шесть назад я писал игры. Точнее, только начинал писать. Сменив около трёх компьютеров, настроив сеть на двух работах, подняв N серверов и перепробовав почти все ОС, в кладовке я нашёл свой старый компьютер c гигагерцовым процессором и установленной Windows XP, а на нём — ту самую папочку с проектами игр. Перебираю, перебираю проекты — и нахожу часть строки:

weaponname="stick" shoot="true"

Компилирую проект. Запускаю. Палка стреляет пулями!

Конечно, про уборку дома я благополучно забыл, но поднял себе настроение и подтвердил высказывание: «Раз в год и палка стреляет».

9525

Задумчиво почёсывая объект

Соискатель на собеседовании:

— Если бы бог использовал при создании человека объектно-ориентированное программирование, то можно было бы, к примеру, удлинить член, разогрев его в микроволновке. Ну, или оставить жопу дома на унитазе, чтобы в дороге не захотелось по-большому. Но бог использовал процедурное программирование, поэтому мы не можем удлинить член или оставить жопу дома. Бог проводил эксперименты с ООП на ящерицах, но, видимо, что-то ему не понравилось, и он оставил всё как есть. Собственно, к чему я это — вот объясните мне, зачем нужно ООП в PHP?