• Смерть в Фейсбуке

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

    Какой плохой Фейсбук.

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

    Лично у меня нет претензий к алгоритму Фейсбука.

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

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

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

    Короче, некрасиво пиариться на смерти человека, к которому не имеешь отношения.

  • Встреча с Егором. Видео

    Егор выступил в клубе Глубокого Рефакторинга:

    Особенно рекомендую второй доклад:

  • Тентакли и прокси

    Значит, купил я ноду на Digital Ocean с целью поднять на ней прокси для обхода блокировок. На LinkedIn зайти, например. Кто не знает, на Маке и Линуксе это делается командой

    ssh -D 8123 -f -C -q -N user@your.ip.address
    

    Далее, чтобы гнать не весь трафик через ноду а только часть (иначе будет тормозить) в Хром ставится расширение Proxy SwitchySharp, которое позволяет менять соединение по правилам. Например, все, что матчится на linkedin.com идет через прокси, остальное – по прямому соединению.

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

    Первая же ссылка говорила за себя: в названии было что-то про аниме, группы и тентакли. Открыл – работает.

    В то же самое время я обсуждал с заказчиком свое увольнение. Отвечая на вопрос в духе “Иван, чем вы думаете заняться после выхода из проекта”, я нажал что-то левое, и ссылка из буфера обмена уходит заказчику.

    А у него в Швейцарии нет Роскомнадзора и некому защитить его от тентаклей.

    Ясное дело, удалил эту ссылку с быстротой молнии, но сих пор не знаю, видел он или нет. Заблокирован ли тот сайт в его стране? Успела ли открыться превьюшка?

    Больше никаких таких ссылочек во время общения с заказчиком.

  • Канал в Телеграме

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

    Вступайте: https://t.me/igrishaev_blog

  • Отвечу на вопросы

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

    Какие вопросы мне задавать? Хотя бы на следующие темы:

    • программирование и разработка ПО,
    • функциональный подход,
    • Кложа, Емакс,
    • работа, в т.ч. удаленная,
    • книги, в т.ч. детские (у меня хорошая подборка книг для детей),
    • организация рабочего времени, “сделывание” задач,
    • переезд в другой город,
    • английский,
    • опен-сорс.

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

    Почта ivan@grishaev.me

  • First Clojure stream in English

    Last Sunday, I tried to stream some Clojure coding commenting it in English. Although I was nervous a bit and thus sounded weird, I think the result worth publishing it here:

  • Разбираемся в часовыми поясами. Инструкция по безопасной работе со временем

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

    Зоны и их преобразования – достаточно тяжелая для изучения тема. Это не проходят в институтах, об этом мало статей на популярных ресурсах. Разработчики учатся работать со временем методом проб и ошибок.

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

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

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

    Пока разработка шла в Лондоне, никто и не думал ни про какие зоны, и код писали без их учета. Разработчик с зоной +3 столкнулся с тем, что не проходит ни один тест, потому что время прибито гвоздями без учета пояса. В итоге коллега проработал у них год сидя с переведенными часами. Было проще поменять зону локально, чем исправить код.

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

    В нашем проекте фронтендер решил, что он умнее системы и что нужно помочь клиенту перевести локальное время в UTC. И тем самым заложил в систему трудноуловимый баг. При отправке объекта Date через Ajax первый автоматически приводится к общемировому времени. Затем срабатывал обработчик коллеги, который тоже корректировал пояс. Получается, что мы дважды вычитали локальное время на клиенте и тем самым портили любую дату с сервера.

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

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

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

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

    Для работы со временем лучше сразу брать хорошую стороннюю библиотеку. Время настолько сложная вещь, что редкий язык может похвастаться качественной коробочной реализацией. В Джаваскрипте объект Date убог. В Джаве класс java.util.Date был объявлен deprecated уже с версии 1.1, то есть почти сразу. Родной datetime в Питоне приемлем только для базовых задач.

    Не нужно думать, что “мне только оберточку написать”, зато без зависимостей. Время – важно. Пусть будут зависимости, но меньше багов.

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

    (Конечно, часовые пояса идут не идеально ровно как полоски на арбузе. Еще недавно в России меняли временные зоны – объединяли и делили соседние. Так, стараниями Медведева в моей родной Чите зимой в 16 часов было уже темно как ночью. Но для простоты будем считать, что пояса распределены равномерно.)

    Поэтому фраза “созвонимся в три часа” в общемировом масштаба не значит ничего. По чьему времени в три часа? По Москве? Нью-Йорку? Очевидно, нужна особая метка чтобы обозначить, откуда это время получено. Тогда путем простых вычислений можно перевести время из одной метки в другую. Эта метка и называется временной зоной.

    Обозначение у нее может быть разное, например смещение в часах (+03:00), имя части света и города через косую черту (Europe/Berlin) или одна из аббревиатур (CET, Центральное Европейское время), но это уже тонкости стандартов кадирования. Важно то, что теперь время привязано к конкретной местности и может быть преобразовано в универсальное время UTC.

    UTC – универсальное координированное время – это современный стандарт отсчета, пришедший на смену GMT. Не будем сейчас разбирать его особенности, достаточно сказать, что на шкале поясов он играет роль нуля: именно от него отсчитываются отрицательные (западные) и положительные (восточные) зоны.

    Например, я живу в Воронеже, мой пояс третий по счету на восток, поэтому я могу написать в резюме “when calling, please consider my +3 UTC timezone” или просто “my TZ is +3”. Тогда заказчик из Лондона, у которого нулевой пояс, добавит к своему времени 3 часа и получит мое локальное время.

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

    Ваш сервер и база данных отвечают за хранение дат. Современные БД (здесь и далее – PostgreSQL) предоставляют два типа полей: это timestamp with time zone и timestamp without time zone, то есть с зоной или без. Если в первое поле записать дату с зоной, то БД сконвертирует ее в UTC, потому что так удобней. А при выводе этой даты в утилитах она будет представлена в локальном времени того пользователя, кто сейчас ее просматривает.

    Рассмотрим пример:

    create table foo (
      ts_z timestamp with time zone,
      ts timestamp without time zone
    );
    
    CREATE TABLE
    
    insert into foo (ts_z) values
      ('2017-12-13T10:00:00-05:00'::timestamp with time zone);
    
    INSERT 0 1
    
    select * from foo;
    

    Результат:

              ts_z          | ts
    ------------------------+----
     2017-12-13 18:00:00+03 |
    (1 row)
    

    Я создал таблицу с двумя полями: время с зоной и без. Потом записал в поле с временной зоной время с часовым поясом Нью-Йорка. В базе оно будет храниться как 2017-12-13 15:00:00 UTC. Но при выводе я увижу время в консоли в моем локальном времени. Все верно, мой пояс +3, дата была приведена верно.

    А в поле ts нужно писать только время по UTC, иначе будет ошибка:

    insert into foo (ts) values
      ('2017-12-13T10:00:00-05:00'::timestamp with time zone);
    
    INSERT 0 1
    
    select * from foo;
    
              ts_z          |         ts
    ------------------------+---------------------
     2017-12-13 18:00:00+03 |
                            | 2017-12-13 18:00:00
    (2 rows)
    

    Видим, что во второе поле записалось не то, что нужно: правильное время по UTC должно быть 15 часов, а не 18. Вот как нужно было сделать:

    insert into foo (ts) values
      ('2017-12-13T10:00:00-05:00'::timestamp with time zone AT TIME ZONE 'UTC');
    
    INSERT 0 1
    
    select * from foo;
    
              ts_z          |         ts
    ------------------------+---------------------
     2017-12-13 18:00:00+03 |
                            | 2017-12-13 18:00:00
                            | 2017-12-13 15:00:00
    (3 rows)
    

    Эта и другие ошибки будут рассмотрены ниже.

    В различных библиотеках и ORM при выборке подобных дат они восстанавливаются в объекты языка с заполненной часовой зоной (поля tz, zone, tzinfo и тд).

    Вариант дат без зон тоже имеет право на жизнь, и на мой взгляд он проще. В команде вы просто соглашаетесь, что все даты хранятся как локальное время по UTC. Все библиотеки имеют функции и методы для работы с таким временем, например, datetime.utcnow() в Питоне, moment.utc() в JS и тд.

    Клиент и сервер должны обмениваться друг с другом только датами в UTC. Универсальное время переводится в локальное на стороне клиента исходя из локального смещения относительно нулевого меридиана. Эту величину можно определить методом .getTimezoneOffset() объекта Date на клиенте.

    При передаче дат клиенту вы кодируете их в ISO-формат с зоной. Если зона UTC, она обозначается буквой Z. Таким образом, в текстовом представлении время, отправляемое клиенту будет выглядеть так:

    "2017-12-12T14:12:23.502Z"
    

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

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

    На этом этапе нельзя не заметить, насколько убог формат JSON: он не может передавать даты и не расширяется.

    В обратную сторону с клиента на сервер даты передаются в таком же формате: ISO-строка в UTC с Z на конце в качестве зоны.

    Рассмотрим, что делать клиенту с полученной строкой. Легче всего восстановить ее в объект библиотекой moment.js:

    moment("2017-12-12T14:20:05.849Z").format()
    "2017-12-12T17:20:05+03:00"
    

    Видим, что все правильно: мой пояс +3, часы были увеличены на эту разницу, на конце индикатор +03:00.

    В сторону: сейчас кто-то встанет и начнет заливать, что moment.js уже не популярен, и что горячие парни пишут какую-то новую либу на замену ей. Мой совет – шлите лесом таких советчиков. Нам нужно проверенное решение, а не модная поделка.

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

    Стоит запомнить: если показ даты требует от вас каких-то махинаций вроде прибавления или вычитания часов, минут или что-то в этом роде – срочно остановитесь, вы гарантированно что-то делаете неправильно. Или должно быть четкое понимание, почему нельзя сделать по-другому.

    При передаче JSON-тела на сервер объект Date не нужно приводить в ISO-строку вручную. Для этого существует метод .toJSON(), который автоматически будет вызван при кодировании внешнего словаря. Например:

    var d = new Date();
    Tue Dec 12 2017 18:40:48 GMT+0300 (MSK)
    
    JSON.stringify({foo: 42, bar: d})
    "{"foo":42,"bar":"2017-12-12T15:40:48.573Z"}"
    

    Рассмотрим основные ошибки, связанные с обработкой времени и как с ними бороться. Начнем с сервера.

    • Тип поля указан timestamp with time zone, но вы передаете объект времени без зоны.

    В этом случае сервер подставит текущую зону, то есть ту, в которой расположен сервер. Если пользователь расположен далеко, например, на другом континенте, это может вызвать значительные неудобства. Скажем, пользователь из Нью-Йорка (-5 UTC) передал на сервер время "2017-12-12T14:20:00Z". Сервер расположен в Швейцарии (+1 UTC). По какой-то причине зона была отброшена, и в базу вместо "2017-12-12T23:20:00 UTC" (исходное плюс 5 часов) записалось "2017-12-12T13:20:00 UTC" (исходное минус 1 час). Ошибка в 10 часов! Представьте, что это напоминания о поездке или рассылка смс.

    • Тип поля timestamp without time zone, но в базу пишется локальное время сервера.

    Убедитесь, что для получения текущего времени вы используете функцию с utc в ее имени, например, datetime.utcnow() вместо datetime.now() и аналогично в других языках. В PostgreSQL аналогично: почти для всех вызовов временных функций нужно указывать зону UTC. Сравните:

    > select current_timestamp;
           now
    -------------------------------
     2017-12-12 19:03:07.683706+03
    
    
    > select current_timestamp at time zone 'UTC';
         timezone
    --------------------------
     2017-12-12 16:04:21.7177
    

    Перевести зону из одной в другую на уровне БД можно следующим оператором:

    select
      '2017-12-13T10:00:00-05:00'::timestamp with time zone AT TIME ZONE 'UTC'
      as right_time;
    
         right_time
    ---------------------
     2017-12-13 15:00:00
    

    Теперь клиент.

    • С сервера приходят UTC-даты в ISO, но без метки Z, например "2017-12-12T14:20:05".

    Попытка отобразить такую дату с помощью moment.js, как мы делали выше, приведет к ошибке:

    moment("2017-12-12T14:20:05").format()
    "2017-12-12T14:20:05+03:00"
    

    Вариантов тут два: либо приклеить к строке со временем нужную зону, либо явно указать библиотеке, что это время в UTC:

    moment.utc("2017-12-12T14:20:05").local().format()
    "2017-12-12T17:20:05+03:00"
    

    Метод .utc() парсит строку с учетом того, что результат будет время по UTC. Метод .local() преобразует его к локальному времени на основании смещения, которое берется из браузера. Теперь все правильно.

    • С сервера приходит его локальное время.

    Это беда, но лечится явным указанием зоны. Например, вы в Москве, а сервер в Нью-Йорке. Он отдает локальное время "2017-12-12T14:20:05". Нью-Йорк в минус пятом часовом поясе. Приклеим зону к строке и распарсим:

    moment("2017-12-12T14:20:05" + "-05:00").format()
    "2017-12-12T22:20:05+03:00"
    

    Значит, это 22:20 вечера по Москве. Проверим устно: если от НЙ до нулевого меридиана 5 часов, а потом еще 3 часа до Москвы, то в сумме 8 часов. 14 + 8 = 22 часа местного времени.

    • Сервер отдает время в виде “unix epoch”.

    Это значит в количестве секунд со дня рождения ОС Юникс – 1 января 1970 года. Такое время всегда представлено в UTC. Отобразить его пользователю можно так:

    moment.unix(1513107997).format()
    "2017-12-12T22:46:37+03:00"
    

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

    Обобщу вышесказанное.

    Научиться работать со временем не сложно. Главное – не оправдывать лень и не дожидаться момента, когда съедут все даты вечером в пятницу. Время – важно.

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

    Храните даты на сервере либо с временной зоной UTC, либо без нее, но подразумевая это.

    Клиент и сервер должны пересылать даты только в UTC с нулевой зоной Z.

    Локальное время выводится на клиенте из UTC относительно локального смещения пользователя.

    При кодировании дат в JSON последний сам позаботится часовом поясе. Вы не должны что-то прибавлять или вычитать.

    Маленький бонус: рассмотрим как быть, если формировать локальное время нужно не на клиенте, а на сервере. До сих пор я вел разговор в том ключе, что у нас Single page application и все рендериться на клиенте. Однако, чисто серверные приложения никуда не делись, и такая задача тоже может возникнуть.

    Представим, что даты хранятся в UTC, но вот пришел HTTP-запрос от какого-то пользователя, и нужно показать даты в его локальном формате. Как быть?

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

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

    Узнать локальное смещение можно через специальный метод объекта Date:

    (new Date()).getTimezoneOffset()
    -180
    

    Оно выражено в минутах и имеет знак противоположный часовому поясу. Если у меня зона +3, то смещение будет -180 минут.

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

    Чтобы привести время UTC в локальное на сервере, достаточно вычесть из первого смещение в минутах. При этом нужно держать в уме знак: вычитание отрицательных минут означает их прибавление, что нам и нужно.

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

    from datetime import datetime, timedelta
    
    utc = datetime.utcnow()
    loc = utc - timedelta(minutes=-180)
    
    utc # datetime.datetime(2017, 12, 13, 13, 57, 18, 108606)
    loc # datetime.datetime(2017, 12, 13, 16, 57, 18, 108606)
    

    Локальное время на 3 часа больше, теперь эту дату можно показывать пользователю.

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

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

    Награда для тех, кто прочел до конца:

  • Пробный стрим про Кложу и Биткоин

    Вчера стримил Кложу. Писал библиотеку-обертку для популярных Биткоин-кошельков: Bitcoin.Core и Electrum. Неплохо пролучилось для первого раза, на мой взгляд. Надо попробовать стрим на английском. Код на Гитхабе.

  • Государство -- враг

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

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

    Значит, выписали мне обычный штраф за превышение – не увидел знак 40 км, проехал на 60. Оплатил в мобильном приложении Сбера. Через месяц падает письмо с Госуслуг: все тот же неоплаченный штраф. Поскольку искать что-то в истории Сбербанка это слезы и боль, решил, что, может быть, не нажал на последнюю кнопку в форме или как-то иначе затупил. Оплатил через Тинькова, на этот раз проверил, что деньги списались.

    Через месяц приходит письмо, что будем тебя судить за неоплаченный штраф. Удаляю. Еще через месяц – смс из Сбера, что со счета арестованы 800 рублей.

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

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

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

    Короче, оценил я затраты времени и сил и плюнул на это дело. Пусть подавятся.

    Через месяц снова арестовывают 800 рублей. Тут уж я решил разорвать колесо Сансары и поехал.

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

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

    Конечно, денег он мне не вернул, но дал бумагу. Езжай с ней в ГИБДД. А вы-то сами, говорю, не в состоянии это утрясти? Нет. Ну и чтоб вас не томить: там тоже стоял, ждал приема, потом мент полчаса тупил в комп и дал последнюю, ультимейт-бумагу, которую нужно отправить в какой-то другой центр ГИБДД.

    А сами-то, бляди, вы не можете отправить? Нет.

    И в общем, через месяц после того как бумагу доставил, приходит заказное письмо: да, вернем вам деньги. И еще через месяц падает нотификация со Сбера, что деньги поступили. Аминь.

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

    Главный вывод: государство не заинтересовано в восстановлении справедливости. Битье по голове работает как часы, все остальное – нет. Если бы это была обычная жалобная заметка, коих в сети тысячи, то можно было бы и закончить. Но я хочу обратить внимание на дизайн всей системы.

    Смотрите, все связи устроены так, что нигде не предусматривается обратное распространение сигнала. Во всех случаях одно ведомство передавало сигнал другому, но как только нужно наоборот – вот тебе бумага, вези на другой конец города. Вы же, менты и банкиры, для нужд внутреннего документооборота не колесите по городу на личном транспорте? У вас же почта, курьеры, приватные сети. Но в обратную сторону ничего не работает.

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

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

    К сожалению, именно так мы и пишем программы. Не тот параметр – упало. В словаре нет ключа – упало, и пусть десять запущенных тредов тоже упадут. Сервер ответил 404 – исключение, программа завершилась. Приложение, как попка-дурак, каждый раз спрашивает одно и то же. Все делай сам: нажимай, логируй, проверяй.

    Никого не волнует, что не ты должен этим заниматься.

  • Бесы

    Отписываюсь от авторов, которые злоупотребляют темой “как же меня бесит”. Особенно когда материал касается людей: не так говорят, не так делают, пользуются не теми программами. Хватит, надоело.

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

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

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

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

    Зачем же ты провоцируешь окружающих? Кому от этого поста стало легче? Число бесящих тебя людей сократилось? Они поняли свои ошибки, исправились?

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

    Еще и пишешь продолжение, что я Д’Артаньян, а вы ничего не поняли. Не профессионально и не по мужски.

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

    Все это останется даже когда вас не станет. А вот как жить так, чтобы ничего из вышеперечисленного на вас не влияло – вопрос гораздо интересней.

Страница 15 из 51