2015-12-27

О времени

Скоро пройдет последняя, 31536001-я, секунда 2015 года. Такая некруглая цифра, на одну секунду больше обычного, из-за того, что 30 июня 2015 года была добавлена високосная секунда. Дело в том, что вращение Земли замедляется, и, чтобы как-то компенсировать это расхождение со временем, которое мы уже давно меряем атомными часами, и вводят дополнительную секунду.
А в 2016 году будет 31622400 секунд, на один день больше, потому что год будет високосный. Это уже из-за попытки согласовать период обращения Земли вокруг своей оси и вокруг Солнца, которые соотносятся как 365.256366004 к одному. Вспоминайте это число всякий раз, когда вас будут убеждать в креационизме.
Но это всё касается григорианского календаря. А если помните, до Революции в России был «старый стиль», благодаря которому мы теперь удачно отмечаем Рождество 7 января. Это — юлианский календарь. Ну а в исламском календаре нынче 1437 год со дня переселения пророка Мухаммеда из Мекки в Медину.
Leap Second
Не так-то просто всё это учесть в наших компьютерных системах. Так что сосредоточимся пока только на григорианском календаре, как наиболее распространённом международном стандарте.
Как хранить дату и время? Казалось бы, очевидно, — хранить числа: отдельно год, месяц, день, и еще часы, минуты, секунды, ну и миллисекунды, если надо. Так и делают. Правда, если хотят сэкономить, и, например, хранят только последние две цифры года, то получается проблема 2000 года. Зато можно, если не нужно время, а только конкретный день, хранить только год-месяц-день. Или наоборот, если интересно время безотносительно конкретного дня — хранить только часы-минуты-секунды.
Таким образом хранят дату-время чаще всего базы данных. В MySQL таковыми являются типы DATE, TIME, DATETIME, а также YEAR. Еще они могут хранить доли секунды с нужной точностью. В PostgreSQL есть DATE и TIME, но нет DATETIME. В Oracle тоже есть DATE, который по сути является DATETIME. В языках программирования тоже используется подобное представление. В Си есть стандартная структура tm, определённая в time.h. В Python имеются date, time и datetime. В C# тоже есть «структура» DateTime. А вот в Java такой структуры нет. Но об этом ниже.
Есть ещё обожаемый мною стандарт ISO 8601 о строковом представлении даты и времени. Вместо того, чтобы мучительно вспоминать, что американцы пишут сначала месяц, а потом день («12/31/2015»), мы говорим, что сначала надо писать год, потом месяц, потом день: «2015-12-31T23:59:59». Замечательной особенностью таких строк является то, что лексикографический порядок их сортировки совпадает с реальным порядком даты-времени. ISO 8601 поддерживается всеми современными СУБД и библиотеками работы с датой-временем для преобразование строки в дату и наоборот.
Gregorian Calendar
Всё хорошо, пока речь идёт о времени в одном месте. Но и тут могут быть тонкости. При переходе с летнего времени на зимнее, когда часы переводятся на час назад, показания часов с часу до двух ночи повторяются. Если мы храним лишь часы и минуты как два числа, возникает неоднозначность. Ну а летнее время еще далеко не везде отменили.
А ещё Земля у нас круглая. Поэтому, когда где-то день, то где-то в это же время — ночь. Где-то уже наступило завтра, а где-то ещё сегодня. Поэтому одних значений даты-времени недостаточно. Необходимо уточнить, в каком именно месте Земли это время. Это и есть часовые пояса или таймзоны.
Взяли Землю, и поделили на 24 дольки. За нуль взяли меридиан, проходящий через город Гринвич. И получилось 24 часовых пояса: от -12 до +12 часов от Гринвича. И стали записывать часовой пояс как смещение от времени по Гринвичу: в Москве (сейчас) — GMT+3, в Омске — GMT+6. Правда, сейчас чаще вместо времени по Гринвичу (GMT) используется всемирное координированное время — UTC. Разница в том, что GMT — это астрономическое понятие, а UTC — это то самое время по атомным часам. Сейчас в компьютерах уместнее говорить именно об UTC и смещении от него.
Итак, мы задаём год-месяц-день-часы-минуты-секунды и смещение от UTC. И однозначно получаем момент времени. И даже при переводе часов мы знаем, что сначала было 1:30 UTC+7, а потом случилось 1:30 UTC+6.
Time Zones
Но есть одна неприятная особенность. Смещение от UTC для данной местности есть величина непостоянная. Тут и летнее-зимнее время, и смены государственных границ, и попытки государств оптимизировать потребление электроэнергии, что выливается то в введение летнего времени, то в отмену летнего времени, то в смену часовых поясов. Чтобы как-то это учитывать, в каждой системе есть некая база данных, которая задаёт часовые пояса в некоторых географических терминах и хранит сведения об изменениях смещения от UTC в данной местности.
В подавляющем большинстве случаев используется база данных часовых поясов, ныне поддерживаемая IANA, также известная как Olson database, или timezone database, или tz database, или zoneinfo database. Это набор свободно доступных файликов, которые уже включены в состав операционной системы, среды выполнения (например, JRE) или библиотеки для работы с датой-временем. В файликах содержатся, например, сведения о том, что «Asia/Omsk» — это нынче UTC+6, до 26 октября 2014 это было UTC+7, а ещё раньше это было летом UTC+7, а зимой UTC+6. Хранятся все подобные исторические изменения в таймзонах.
Кроме длинных имён таймзон вроде «America/New_York» часто используются сокращения вроде «EST» (Eastern Standard Time — стандартное время на восточном побережье США, где Нью-Йорк как раз находится) или «EDT» (Eastern Daylight Time — летнее время на восточном побережье США). Как правило, инструменты работы с датой-временем прекрасно понимают подобные сокращения. Однако, я предпочитаю их не использовать, ибо понятны они в основном только местным жителям, неоднозначны, и, кроме того, сами местные жители часто употребляют их неправильно, например, летом говорят EST, хотя технически более верно говорить EDT.
End of Daylight Saving Time
Несмотря на то, что и смещение от UTC, и название географической местности — это таймзоны, надо эти два понятия различать. Смещение от UTC позволяет однозначно идентифицировать момент времени, заданный в виде года-месяца-дня-часа-минуты-секунды. Это очень хорошо для хранения момента времени, нет неоднозначностей. А имя часового пояса задаёт правила преобразования и отображения даты-времени в данном окружении. Часовой пояс может различаться для каждого пользователя системы, и надо корректно отобразить дату-время в часовом поясе именно данного пользователя, независимо от того, как мы эти дату-время сохранили ранее. И при этом будут корректно обработаны исторические перепетии местного законодательства.
Основная боль в работе с базой таймзон — её актуальное состояние. IANA-то отслеживает изменения в мире, и свежие версии появляются в худшем случае за пару месяцев до вступления изменений в силу. Но вот эти обновления очень долго проникают в реальные системы. Хорошо, если у вас какой-нибудь Linux с актуальной поддержкой. Тогда системные пакеты с базой таймзон сами прилетят с обновлениями. Плохо, что, например, Java поддерживает свою версию этой БД. И если вы не озаботились о ручном обновлении, вы можете получить изменения слишком поздно. Отдельную разновидность глюков порождают разные версии базы (читай, JRE) на разных окружениях.
Еще раз, не нужно использовать «географические» названия часовых поясов для хранения даты-времени в БД. Здесь возможны неоднозначности при переходе на летнее-зимнее время, полностью аналогичные описанным выше. «2015-11-01T01:30» в «America/New_York» — это UTC-4 или UTC-5? Поэтому в ISO 8601 можно задать только смещение, чтобы однозначно определить момент времени. «2015-11-01T01:30-05» и «2015-11-01T01:30-04». А для самого UTC (нулевое смещение) используется специальная буква «Z»: «2015-12-31T23:59:59Z».
Базы данных и библиотеки для работы с датой-временем умеют работать с часовыми поясами. В C# DateTime можно задать либо в UTC, либо в «локальной» (то бишь, установленной в данной ОС) таймзоне. В SQL есть типы данных с пометкой WITH TIME ZONE. Однако, это не означает, что в БД будет хранится смещение от UTC. Тут всё хитрее. И сильно зависит от БД.
Unix Timestamp
Есть ещё один способ задания даты-времени. Мы просто берём некий момент времени: эпоху или начало эпохи — и начинаем считать секунды или миллисекунды от этого момента. И получаем просто число, которое однозначно указывает на некий момент времени, с секундной или миллисекундной точностью. В Unix за начало эпохи взяли 1 января 1970 года UTC (полночь, начало этого дня). И секунды с этого момента принято называть Unix timestamp.
Замечательной особенностью такого указания даты-времени является то, что оно совсем никак не зависит ни от таймзон (начало эпохи определено в UTC), ни от календаря. Число секунд легко (компьютеру) перевести в часы-минуты-секунды любого часового пояса и в год-месяц-день любого календаря.
К недостаткам можно отнести проблему 2038 года. Если счётчик секунд у нас — 32-битное знаковое целое, то 19 января 2038 года этот счётчик переполнится. Но это не сильно большая беда, ибо всё чаще используется 64-битный счётчик миллисекунд, который переполнится в 292278994 году, на наш век хватит.
Именно таковым является класс Date в Java. Единственное, что он хранит, — это счётчик миллисекунд от начала Unix эпохи типа long. То, как Date отображается в IDE, зависит от окружения, в котором запущена IDE, включая часовой пояс и локаль операционной системы. То, как Date будет выглядеть где-нибудь на сервере (что вернёт его метод toString()), зависит от окружения сервера: его часового пояса и локали, а также актуальности его базы часовых поясов. Но это всегда будет конкретная миллисекунда от начала эпохи.
Аналогичные типы есть в базах данных. TIMESTAMP в MySQL. TIMESTAMP и TIMESTAMP WITH TIME ZONE в PostgreSQL, тут началом эпохи принято 1 января 2000 года, а суффикс WITH TIME ZONE влияет на преобразование дат при записи и чтении (учитывая часовой пояс клиента БД). TIMESTAMP в Oracle.
Real Timestamp
Так как метка времени — лишь число, возникает соблазн произвести арифметические действия над этим числом. Не надо так.
Вам может захотеться прибавить или отнять 3600 секунд, чтобы «подкорректировать» часовой пояс или летнее/зимнее время, которые у вас отображаются «неправильно». Это категорически неверно. Метка времени не содержит никакой информации о часовом поясе. Прибавление секунд переставляет эту метку на другой момент времени, совсем другой. А отображаться она может не так, как вы ожидаете, по двум причинам. Либо у вас уже есть неправильные данные, и тогда их надо поправить, а не подкручивать на лету. Либо у вас стоит неверный часовой пояс, либо база данных часовых поясов устарела. Для проверки правильности метки времени можно воспользоваться стандартными командами.
Отобразить метку времени в человекочитаемом формате:
 % date -d "@1451584799"              
Thu Dec 31 23:59:59 OMST 2015
 % date -d "@1451584799" -u
Thu Dec 31 17:59:59 UTC 2015
 % TZ="America/New_York" date -d "@1451584799"
Thu Dec 31 12:59:59 EST 2015
Преобразовать дату-время в метку:
 % date -d "2015-12-31T23:59:59" "+%s"
1451584799
 % date -d "2015-12-31T23:59:59Z" "+%s"
1451606399
 % date -d "2015-12-31T23:59:59-05" "+%s"
1451624399
А ещё вы можете захотеть перейти к следующему часу или дню. Запомните, добавлять 86400 секунд к метке времени, чтобы получить завтра, — это так же глупо, как добавлять 30 дней, чтобы получить то же число следующего месяца. Про то, что в месяце может быть совсем разное число дней, помнят все (а вы точно помните, какой год считается високосным в григорианском календаре?). А про переход на зимнее-летнее время все почему-то забывают. Ну и я вам еще рассказал про високосные секунды.
Чтобы правильно переходить от одной даты к другой применяются специальные методы, тесно связанные с используемым календарём. Часто это специальные типы данных, предназначенные для кодирования интервалов времени. Тогда к типу, представляющему дату-время, можно добавить или отнять тип, представляющий интервал, и получить новую дату-время. Таков класс TimeSpan в C#, timedelta в Python, INTERVAL в PostgreSQL и Oracle. Используйте их. Даже в ISO 8601 есть синтаксис для интервалов: например, «P3Y6M4DT12H30M17S».
А в стандартной библиотеке Java таких классов нет. Потому что нет переопределения операторов, наверное. Зато есть класс Calendar, который делает то, что нужно. Есть методы для установки года-месяца-дня-часов-минут-секунд. Есть методы для чтения их же. Есть методы для добавления годов-месяцев-дней-часов-минут-секунд. Ну а на входе или выходе можно получить стандартную метку времени — Date. В общем-то, всё что нужно, если достаточно григорианского календаря. Ведь что такое «последний день текущего месяца»? Это взять сегодня, добавить месяц, взять его первое число и отнять день.
Все эти метки времени, часовые пояса, базы данных таймзон и прочее, конечно, имеют смысл только если вы работаете с новейшим временем. Т.е. с тем временем, который используется в 99% софта. Но если вам нужно датировать исторические события до нашей эры, или наоборот, события, связанные с продолжительностью жизни звёзд, вероятно, вам понадобится и другой, вовсе не григорианский, календарь. Да и миллисекундная точность не нужна будет. Вероятно, тут нужны более специальные решения.
Creation of Light
Подведём итог.
  • Если вы храните дату в виде года-месяца-дня-часов-минут-секунд, вам просто обязательно явно указывать смещение этих значений от UTC.
  • Или же соблюдать соглашение о том, что все значения даты-времени будут в UTC.
  • Или же хранить стандартные метки времени, не привязанные к часовому поясу.
  • Внимательно читайте документацию к типам данных вашей БД, хранение даты-времени везде сделано по-разному.
  • При преобразовании входных значений в дату-время, при преобразовании даты-времени в человекопонятные значения обязательно явно указывайте часовой пояс из базы часовых поясов, не полагайтесь на умолчательные значения, они могут различаться в разных окружениях.
  • Используйте длинные имена из базы данных часовых поясов, не используйте сокращения.
  • Не используйте типы даты-времени, привязанные к окружению или не содержащие часовой пояс (типа LocalDateTime). Всегда считайте, что ваш код может быть запущен на сервере с совершенно левой таймзоной и должен обслуживать пользователей по всему миру.
  • Следите за актуальностью базы данных часовых поясов.
  • При преобразовании даты-времени в строку, кроме часового пояса вам понадобится еще и явно указать локаль.
  • Используйте ISO 8601 на входе и на выходе, если нет явных указаний на локализацию (например, в логах или для указания даты-времени в API).
  • Никогда не производите арифметических действий с метками времени, годами, месяцами, днями, часами, минутами и секундами. Никогда не пытайтесь сами высчитать високосный год или переход на летнее/зимнее время.
  • Используйте стандартные библиотеки для работы с датой-временем, и только их. Не пытайтесь изобрести велосипед. Следите за актуальным состоянием базы данных часовых поясов.
  • Могут быть библиотеки, более удобные, чем стандартные (например, JodaTime). Решайте сами, нужна ли вам дополнительная библиотека только ради удобства.
  • В редких экзотических случаях (работа с не григорианским календарём) вам могут понадобиться дополнительные библиотеки вроде ICU.
  • Всегда синхронизируйте время на серверах, NTP в помощь.
  • При отладке и сопровождении, а также по жизни, не запутаться в часовых поясах поможет timeanddate.com.

2015-12-13

О HappyDev'15

Подготовился, начался, случился и завершился очередной, пятнадца... ой, четвёртый HappyDev. Это такая омская сибирская айтишная конференция для омичей и их иногородних друзей. Которая по традиции проходит за городом, на местной базе отдыха имени Ивана Стрельникова.
HappyDev
По традиции был концерт. На этот раз очень шумной и энергичной омской группы Радости и Счастья Цемент-BanD. Ребята вполне дают жару, сильно не хуже ульяновских групп, что я слышал на UlCamp.
По традиции был открытый бассейн с неприлично мутной, но лечебной йодо-бромной водой. Правда, плавать в -3°C всё же не так весело, как в -30°C. Была хорошая пионерлагерная еда, с много каш и супов.
Ну и, в нарушение традиций, были собаченьки. Лайки появились на символике конференции. А хаски, самоеды и маламуты захватили половину официальных фоточек и почти весь Инстаграм, они фотографировались вместе с участниками.
Ой нет, в Инстаграме еще засветился лазертаг. Это когда две толпы народу, с пластмассовыми автоматиками и лампочками на голове, бегают по лесу под звуки «пиу-пиу» и «тра-та-та».
Ёжик в туманности
Ах да, конференция. Айтишная!
В этот раз идея была такая. Дать докладчикам кратко высказаться по теме для широкой аудитории. А для интересующихся техническими подробностями организовать мастер-класс. Длинный, на два-четыре часа. Похоже, получилось. Мастер-классы пользовались популярностью, и участникам нравилось.
Мой небольшой организаторский вклад в этом году заключался в насильственном вытягивании из докладчиков материалов к мастер-классам (старались, чтобы это были образы виртуальных машин, которые бы работали без интернетов) и добровольной раздаче их участникам. Это я решил раздавать файло через BitTorrent Sync. Прошу не бить.
Открывал конференцию матёрый омич-петербуржец Лёша Зиновьев. Рассказывал про большенькие данные. Интересующимся темой, но не желающим погружаться в айтишную тематику, могу порекомендовать соответствующую книгу. Таки Big Data уже здесь и сейчас, и всех победят. На мастер-класс, где, говорят, можно было воочию понаблюдать, как работают страшными хадупами и спарками, я, к сожалению, не попал.
Послушал, как Данил Никифоров рассказывал про решение для синхронизации данных мобильных приложений от Couchbase. Типа запускаем NoSQL базу Couchbase Lite на девайсе, запускаем Couchbase Sync Gateway где-то на облаке, и всё ваши милые данные синхронизируются в облачный же Couchbase Server. В общем, ничего нового, я об этом слышал ещё два года назад. Оно всё, может быть, и хорошо. Но меня напрягает обилие слова «Couchbase» во всём этом. Какой-то типичный vendor lock.
С удовольствием послушал доклад и посетил мастер-класс Вадима Литвинова из дружественного Новосибирска. Он рассказывал про MZBench — штуку, которую они написали для нагрузочного тестирования своей мобильной игрули Game of War, серверной её части. Тема распределённого нагрузочного тестирования близка моему сердцу. Было интересно увидеть и даже чуть-чуть пощупать, что получилось у Machine Zone.
Получилось неплохо. Произвольные сценарии тестирования, на Erlang или Python. Автоматизированное развертывание узлов для генерации нагрузки (в первую очередь, в Amazon). Автоматизированный деплой и запуск кода нагрузки. Автоматизированный сбор и отображение метрик. Оказывается, существует аддитивный способ сбора данных, чтобы потом получать аггрегированные персентили (это страшная математика, в которую мне самому еще предстоит погрузиться :) Очень красиво выглядит идея писать код нагрузки совершенно произвольно, но чтобы результатом его работы были определённые метрики. Только мне хочется полностью асинхронной нагрузки. И вообще, возникло желание написать свой универсальный сборщих системных метрик, а ля Diamond, но на Node.js (асинхронный), и с полноценной поддержкой тегов в стиле InfluxDB. Пока борюсь с собой.
Свой омский Коля Линкер устроил мастер-класс по монадкам. Что они такое, я в точности не понял. Ну вроде как интересный фокус в функциональном стиле. Но почему ему придают такое большое значение? А вот проникнуться Хаскелем (это не собаченьки!) вроде удалось. Понравилась мощь выведения типов. Понравилось, что типы и определения записываются отдельными строчками. Как-то понимаешь, что всякие споры о том, как кошернее записывать типы: в Си-стиле (до имени переменной) или в Паскаль-стиле (после имени переменной, через двоеточие), и в каком случае допустимо имя типа упускать, ибо выводится, — это всё ни о чём, на фоне Хаскеля.
Анатолий Орлов из бывшего Яндекса поведал об, в общем-то, известных тонкостях работы TCP. Речь о размере окна подтверждения. В TCP на каждый переданный пакет ожидается подтверждение его приёма. Если ожидать подтверждения прямо для каждого пакета, то скорость передачи будет ну оооочень низкой, ибо придётся ждать, пока пакет уйдёт туда, пока придёт подтверждение оттуда, и лишь затем посылать следующий пакет. Время пересылки пакета тут критично, а его уменьшить до нуля нельзя, таки скорость света. Поэтому TCP шлёт сразу несколько пакетов без подтверждения, а потом заполучает подтверждение для всех сразу. Вот количество этих самых пакетов, которые можно отослать без подтверждения, и есть размер окна.
Если размер окна маленький, то передача будет идти медленно. Но если размер окна большой, возникает другая проблема. Если при передаче возникли ошибки или подтверждение затерялось, то нам придётся слать все пакеты окна заново. Это снова снижает скорость передачи. По-хорошему, размер окна надо подстраивать под текущее качество (количество потерь) канала связи. Собственно, всё оборудование и софт, работающий с TCP, так и делают.
Но тут возникает другая тонкость. Качество канала от вас до сервера может сильно различаться. Типичный современный пример: хорошая оптика от вашего домашнего маршрутизатора до интернетов и плохонький вайфай до ноутбука. По идее, по оптике нужно большое окно, а через вайфай передавать с маленьким окном, в ожидании частых потерь и повторов передачи. Да вот только TCP определяет один единственный размер окна на всю TCP сессию, от ноутбука до сервера в интернетах.
Решение: разбить TCP соединение на вашем домашнем маршрутизаторе, запустив на нём, скажем, кэширующий HTTP прокси. Помнится, на заре интернетов по выделенке я примерно такое и делал. Была обратная ситуация: были потери у провайдера. Я поднял у себя прокси и кэширующий DNS (ибо потери DNS запросов оочень сильно тормозит пользование интернетами), и стало гораздо веселее.
Александр Рожнов рассказал про Docker и Kubernetes. Первое — это популярная система контейнеризации и распространения образов под Linux. Второе — среда распределённого разворачивания контейнеров. Я не запомнил, что было на докладе. Интересней были последующие мастер-классы. Кто был — были в восторге. Я — пропустил.
Под конец субботы в главном ангаре выступал известный джедай-практик Максим Дорофеев. Он рассказывал, в общем, всё о том же, рисовал неприличные надписи на сцене и проводил сеанс групповой депрокрастинации. Сеансу я предпочёл бассейн, ибо полгода назад уже участвовал в более серьёзном тренинге. Честно говоря, я удивлён, как ещё находятся люди, которые не только не начали приводить свои дела в порядок, но даже не слышали, кто такой Дорофеев. Видимо, в ближайшие годы стабильный заработок Максиму гарантирован.
Ass Raptor
В воскресенье утром сходил на доклад Алексея Букурова про генерацию интерфейсов. Извините, чуть не уснул. Не понял, зачем, о чём и с какой стати. Не зачем это было сделано, а зачем так скучно об этом докладывать.
Дальше в главном зале пошли подряд три доклада архитектурной направленности. Начал крутой чел из омского Люксофта — Максим Юнусов. Вроде, всё правильно говорил. Есть паттерны и антипаттерны... Нет абсолютно правильных архитектурных решений... Но что-то слишком часто звучало слово «антипаттерн». По мне, так паттерны существуют, наносят пользу или приносят вред, независимо от того, найдётся ли умный дядька, чтобы описать их в своей книжке, или найдётся ли другой умный дядька, чтобы в другой книжке написать, что этот паттерн — говно. А еще мне показалось, что докладчик явно не договаривает, возможно, в желании не нагружать аудиторию. Ведь, кроме процедурного да ООП, есть ещё функциональное программирование да те же акторы. Ведь, после джуниоров, сениоров и архитекторов-прагматиков, где последних заботит правильность реализации технического решения, есть еще две ступени заботы: забота о нуждах заказчика и забота о конечных пользователях.
Кстати, об акторах. Продолжил Антон Тарасенко. Они в Тамтэке, на основе практических нужд реальных проектов, родили маленький легковесный фреймворк для асинхронного программирования. Половина доклада была посвящена преимуществам асинхронности. Другая половина — конкретному решению для объединения CompletableFuture в пайплайны для обработки сетевых запросов. Стоп. А акторы ли это? Это больше похоже на LINQ и ленивые вычисления. Ну или на маленький Apache Spark, если хочется так думать. Вроде красиво, но хочется мастер-класса :)
Забегая вперёд, забавно видеть, как одни и те же вещи называются в разных решениях по-разному. Context — Message. Pipeline — MessageMap. Service — Actor.
Ну и Евгений Тюменцев. Широко известный в узких кругах не только Омска архитектор-учёный-революционер-преподаватель. Он рассказывал про свою реализацию акторной модели, которая была подтверждена реальными внедрениями, в разных инкарнациях существует уже лет шесть, и сейчас переписывается на Java.
Мне тяжело тут пересказывать. На самом деле, я знаю об этой реализации несколько больше участников конференции. Впервые о ней услышал года два с половиной назад, а последние полгода мимо меня постоянно ходили непосредственные разработчики этого чуда. Тем интереснее было наблюдать за реакцией зала. Кажется, кто-то был шокирован, а кто-то возмущён. Прекрасно!
Удивление
Главное тут — SOLIDность. Мы делаем систему согласно всем SOLID принципам. И получается конструктор — набор кубиков, из которых можно сделать всё что угодно. Мы не сверлим дырки в существующих кубиках и не работаем напильником. Если нам нужен новый функционал, мы делаем новый кубик и ставим его на нужное место. В серьёзных базах данных, от CRUD уже давно используется только C и R. Мы никогда не модицифируем и не удаляем данные, мы создаём новые версии или помечаем на удаление.
Так же должно быть и с кодом. Пишем новый код и подключаем его к системе. Но никогда не правим старый. Именно поэтому плохи ifы, switchи и enumы. Изменение требований (условий окружающей среды) требует изменения подобных конструкций. Их невозможно расширить, не переписав код, не потеряв старый код, который работал, блин, и был весь протестирован. А вот справочники, таблицы переходов, в конфиге или в базе, перегруженные методы, различные реализации интерфейсов — зер гут.
Вот SOLIDная реализация акторной модели и даёт инструмент для создания и склеивания кубиков. Кубики просты, понятны, могут быть независимо оттестированы. Старые кубики никуда не деваются и могут функционировать одновременно с новыми. Ну а ядро системы, собственно, система управления акторами, будучи раз правильно написана, не меняется. Пуля не серебряная. Но всё же?
Lego New Hope