В первой части статьия долго рассказывал вам, как все плохо и вообще — почувствовал себя вестником Апокалипсиса. Это, безусловно, интереснее и веселее, чем предлагать решения. В конце концов, у нас вообще любят соглашаться с тем, что все вокруг плохо. Но такой подход (видеть только беспросветный трындец вокруг) отдает инфантилизмом. И я, рискуя навлечь на себя тонны обвинений в (скажем мягко) необразованности, продолжу свои речи о том, что же со всем этим делать.
И начать надо, естественно, с обзора деталей того, что сейчас предлагает рынок и академическая среда.
Сложность
Самая первая проблема, я бы сказал — мать всех проблем — это сложность. Сложность всего — от предметной области до архитектуры самих Enterprise-приложений. И эти сложности наслаиваются и вызывают друг друга. И умножают друг друга. Поэтому давайте с них и начнем.
Сразу скажу, я не претендую на какие-либо академические познания. Я — обычный руководитель небольшой софтверной компании. Однако я в этом бизнесе давно (уже больше 20 лет) и информацию искать вроде бы умею. Более того — я вообще интересуюсь Computer Science. В любом случае так я вижу ситуацию. Если я ошибаюсь, можете меня поправить — я открыт к новой информации.
Итак, результат моего исследования таков: в академических кругах вокруг проблемы сложности сплошное бла-бла-бла. То есть буквально: «Вот у нас гистограмма сложности задач, а вот у нас график роста сложности, давайте теперь наложим их друг на друга и будем медитировать на результат». Я вполне допускаю, что результатом этих «наложений» и «медитаций» рано или поздно станут какие-то практические рекомендации, но пока одно сплошное балабольство.
В бизнесе все еще хуже. Со сложностью здесь никто не борется. Ею даже в чем-то гордятся — у нас тут все так сложно! Более того, если вы придете к вашему руководству и начнете объяснять, что сложность — это плохо, с ней надо бороться, упрощая и стандартизируя все и вся, вам скорее всего скажут: «Ты что, НЕ ТЯНЕШЬ?!». Да, у нас сложно. Но мы СПРАВЛЯЕМСЯ.
Проблема усложняется тем, что Enterprise-приложения растут как трава при дороге — без единого плана и вообще без какого-либо видения общей картины. Нам потребовался вот такой функционал — мы его запилили прямо здесь и сейчас, не думая о том, что этот функционал понадобится еще в нескольких других местах и там его придется либо делать заново, либо банально копипастить. Вынесение чего-либо в общие части (shared services) в большинстве случаев затруднено, так как выходит за пределы компетенции руководителей отделов заказчика — такая часть уже непонятно кем должна сопровождаться. В смысле — была часть системы, относящаяся к компетенции одного отдела и часть, относящаяся к другому отделу. А к чьей компетенции должна относиться общая часть? Уже непонятно.
Вообще, проблема с отсутствием ответственных тесно переплетена со сложностью. Если никто не отвечает за систему в целом — кто же будет переживать, что система сложная? Никто, естественно. Каждый удельный князек в своей части системы вполне способен разобраться.
Итак, что же я предлагаю делать с этой проблемой:
- Взять цель на упрощение предметных областей, стандартизуя термины и их определения, отбрасывая дублирующие понятия и определяя все термины максимально жестко, без возможности многозначного трактования. Я понимаю, что компании привыкли работать в понятийном хаосе (не верите — почитайте документацию IBM, там ад виден прямо сразу), однако необходимость таких изменений даже не назрела, а перезрела.
- Выделение ответственных. Я, как человек, который более 20 лет занят в разработке и более 15 лет руководит программистами, могу сказать точно одно: если для какого-то дела не назначены ответственные, то это дело с места не сдвинется НИКОГДА. И вопрос не в том, что люди плохие. Вопрос в том, что у всех есть своя работа, за которую с них и спрашивают. А за работу по упрощению предметной области, стандартизации, обмену информации и т. д. — ни с кого не спрашивают. Значит никто ею и не занимается, потому что всегда есть более важная работа. Так вот. Надо наконец признать проблему и выделять отдельных специалистов (группы специалистов), отвечающих именно за систему в целом. Только в этом случае мы можем рассчитывать на позитивные изменения.
- Поддержание актуальности и полноты архитектурных документов. Если есть на свете что-то, что программисты любят меньше, чем писать юнит-тесты, — так это написание документации. Как часто шутят в Enterprise — программа отлично документирована на языке Java. Так вот, эта ситуация недопустима. Документирование системы должно стать важнейшей частью ее разработки. Архитектурные документы, особенно UML-диаграммы (с любой степенью детализации — от саб-систем до уровня кода) должны быть легко доступны любому разработчику и быть единственным источником информации по архитектуре приложения. Естественно, такой подход потребует разработки массы дополнительных правил и методик. И это дело не одной статьи. Однако начинать этим надо заниматься именно сейчас, а лучше — вчера. А не тогда, когда системы перестанут справляться с нагрузкой.
- Стандартизация — одно из самых простых и отлично зарекомендовавших себя средств для борьбы со сложностью и гетерогенностью. Каждый, я думаю, прекрасно помнит, как 10 лет назад, входя в офис, кричали: «А у кого зарядка от маленькой нокии? Нет, плоская не подходит». Ничего, как-то стандартизовались — живем. Всем вроде бы удобнее стало. Меня же, честно говоря, несколько обескураживает то, что в нашей сфере процесс идет в обратную сторону. Вот, например, история интеграции. Вместо стандартной до скрежета зубовного CORBA, пришли более мягкие, но все же стандарты SOAP, а на смену им — REST, про который единственное, что можно сказать: «Это не протокол и не стандарт, а архитектурный стиль». Стиль такой. В смысле «я художник, я так вижу». И если интеграция REST с JS мордой или мобильным приложением выглядит ок (преимущества JSON для этой интеграции очевидны), то участившиеся в последнее время случаи интеграции В2В приложений с помощью REST выглядят совершенно не лучшим вариантом. Ну в любом случае стандартизация — наше все.
- Обмен информацией — краеугольный камень решения самых тяжелых и неприятных проблем в разработке. Как показывает моя практика, разработчики крайне редко общаются на производственные темы с коллегами не из смежных проектов. Да и с коллегами из смежных — только по необходимости. Что я предлагаю сделать для исправления ситуации:
- Кросс-командные митинги. Работа над любым проектом практически не бывает полностью ровной — чаще случается то густо, то пусто. Так вот, было бы хорошо тратить время, когда «пусто» на то, чтобы подготовить короткую презентацию архитектуры и основных технических решений для смежников. И обратиться к ним: «Хотите, мы вам расскажем про свой проект? Коротенько — на час-полтора, больше не надо». А потом попросить, чтобы вам презентовали свой проект. Слушатели будут заинтересованные — в конце концов, всем интересно, над чем работают коллеги из соседней комнаты, тем более если у вас еще есть и интеграция. Можно набраться каких-то знаний по типовым решениям, да плюс еще — блеснуть своими знаниями. Если проводить такие встречи достаточно часто, то обмен информацией внутри компании улучшится в разы.
- Общие вики. В любой компании со временем накапливаются тонны информации по взаимодействию с легаси софтом заказчика, по правильному использованию сложившейся инфраструктуры с учетом ограничений секьюрити. Неприятно, что большинство этих мелких решений так и остаются в голове того, кто их нашел. Ну максимум — в своей команде. Естественно, такие знания надо аккумулировать и делать общедоступными (в рамках компании, конечно). Как по мне, самое удобное на этот момент решение — это движок вики. Насколько мне известно, во многих компаниях такие вики стоят, однако используются они крайне редко, и информация там бывает уже давно не актуальной. Как обычно, решение такой задачи упирается в отсутствие ответственных. Я бы предложил подчинить вики специалисту (или группе), отвечающему за общую архитектуру (я рассказывал об этом в пункте 1).
- Обучение корпоративным стандартам. Никакая стандартизация невозможна, если непосредственные исполнители не знают о существовании стандарта. Вообще, я, как специалист по обучению, с грустью вынужден констатировать практически полное отсутствие работы в разработческих компаниях над образованием сотрудников. Обучение, которое проводится, часто делается для галочки, средствами собственных сотрудников и результат назвать, кроме как «из вторпродукта и палок», сложно. А если говорить о собственно обучении корпоративным стандартам... Ой, а они вообще в каждой компании существуют?
Монолитность
Монолитность в последние годы — любимый объект для борьбы (про страсть искать не там, где потерял, а там, где светло, я уже писал). Ну так вот. Тут место, где светло, точнее золотой молоток (прибегая к другой аналогии) нашелся. Это были... вы уже догадались? Да-да. Микросервисы, конечно.
А раз у программистов есть прекрасный золотой молоток — так монолитность тут же объявлена главным злом, и с ней борются, причем нельзя сказать, что безуспешно.
Однако и здесь есть несколько проблем, которые старательно игнорируются. Я бы обратил внимание на следующие из них:
- Возникает дополнительная гетерогенность. В большинстве своем на SOA/микросервисы переводят не все Enterprise-приложение, а только небольшую его часть, а чаще всего — только один модуль. В результате монолитность всего приложения никуда не девается (от монолита откусили только маленький кусочек), а вот гетерогенность всей системы увеличилась. Нельзя сказать, что это так уж хорошо. Ну и мы можем прогнозировать, что с появлением новых подходов части проекта, сделанные на SOA/микросервисах так и останутся жить памятниками своего времени, как и кучи наслоений, сделанных на золотых молотках своего времени.
- От введения дополнительной архитектуры в проект, сложность всего проекта явно не уменьшится. Более того, само приложение на микросервисах часто оказывается сложнее для понимания, чем монолитное.
- Последняя проблема микросервисов и при этом самая важная, на мой взгляд, — такая архитектура не решает проблему монолитности сама по себе. Если архитектура микросервисного приложения не продумана, то на самом деле все проблемы просто поднимаются на сетевой уровень и прячутся от взгляда разработчиков. То есть если раньше разработчики вынуждены были думать над архитектурой хотя бы своего модуля, то теперь, когда модуль распался на кучу микросервисов, над их общей архитектурой можно не задумываться — так как непонятно, кто за все это вообще отвечает. Да, в теории должен отвечать тимлид или архитектор, однако я видел полно команд, где архитектора не было, а тимлид этим не волновался. Ну и все, уже модуль начинает расти как трава под забором, принимая все проблемы, перечисленные в первой статье.
Есть еще несколько менее очевидных и менее важных проблем. Для примера приведу одну. Если вы разрабатываете монолитное приложение, то фактически уже сложился консенсус про совместное владение кодом, и рано или поздно другой программист влезет в кусок кода, который вы написали, и спросит: «А это что за фигня?». С микросервисной архитектурой большинство команд проваливается в кошмар персонального владения микросервисами: когда у каждого сервиса есть владелец, и только он его меняет. В принципе, понятно, к чему это приводит.
Это все не значит, что я против микросервисов. Наоборот — и сама идея, и многие ее реализации мне кажутся действительно хорошим направлением движения. Однако надо помнить о том, что решение проблемы никогда не бывает таким простым, как только использование нового инструмента.
Мои предложения по борьбе с монолитностью:
- Официальное разделение частей бизнеса. Сложно добиться модульности Enterprise-приложения, если оно является полным отражением запутанного, как клубок ниток, бизнеса. В идеале необходимо добиться, чтобы интеграция между частями Enterprise-приложения, относящимися к ведению разных департаментов, происходила точно так же, с такой же глубиной документирования и стандартизацией, как интеграция с внешними системами.
- Стандартизация способов интеграции. Вы уже, наверное, заметили, что я предлагаю все стандартизовать. И это действительно так. Если нам необходимо бороться с монстром в виде запутанного клубка взаимодействий разнородных частей, то давайте хотя бы добьемся, чтобы части были относительно стандартные и взаимодействие их было однотипным. Я имею в виду, если у вас все части интегрируются по SOAP, например, то давайте и новую интеграцию сделаем на нем же. Даже если SOAP тут явно избыточен.
- Единый реестр микросервисов. Эту идею мне рассказал один слушатель во время выступления. Он сказал, что в их компании считается, что микросервис готов только тогда, когда автор завел его в общий реестр микросервисов компании. С полным описанием — что за сервис, какие у него интерфейсы, что он возвращает и что делает. Идея кажется мне просто гениальной. С одной стороны, сервис описывает сам автор, что предотвращает неверную трактовку (автор-то точно знает, что он написал... я надеюсь на это). Плюс к этому мы достаточно хорошо понижаем риск того, что готовая функциональность будет разрабатываться еще раз. Повышаем реюз готовых сервисов и еще много всякого хорошего. И все это ценой небольшого нытья программистов, что «неохота всю эту ерунду писать». Рекомендую делать также. Меня еще спрашивали: может, лучше сделать систему автоматического дискавера сервисов? Я считаю, что нет, не лучше. Как минимум вы потратите тонну времени на эту систему. Но программисты все равно напишут такой сервис, который будет дискавериться неверно. Плюс к этому — вы не получите комментариев от автора сервиса, а они часто — самое важное.
- Даже если вы не хотите вести общий реестр микросервисов, в любом случае необходимо на уровне организации утвердить список необходимой информации, которая должна быть в документации по каждому микросервису.
Гетерогенность
Как я уже писал в первой части статьи, гетерогенность в большинстве случаев игнорируется и часто даже приветствуется как фича, а не баг, а то и ставится в заслугу. У нас тут столько всяких технологий на проекте!
А вообще мы знаем, как программисты борются с проблемой гетерогенности: у нас есть новый золотой молоток (new shining thing, по меткому выражению Роберта Мартина), так давайте все сделаем этим новым золотым молотком. А поскольку сейчас у нас любимый золотой молоток — микросервисы, так давайте все сделаем на микросервисах. Но о проблемах этого решения я писал в прошлой главе, повторяться не буду.
Если проанализировать требования к Enterprise Java разработчикам по вакансиям, то мы увидим, что рынок уже свое слово сказал: ставка на сегодняшний момент сделана на стек фреймворков Spring. Я обычно приветствую любую стандартизацию. Но вот как раз к стеку спринга у меня есть несколько претензий:
- Спринг навязывает стиль архитектуры. Сделать, например, rich domain model на спринге практически нереально (правда, как и на стеке Java EE). Эта проблема достойна отдельной статьи, если вам интересно, о чем я — напишите в комментариях, я тогда выдам свои мысли по поводу того, как современные Enterprise-стеки фреймворков издеваются над ООП.
- Spring настойчиво пытается проникнуть во все части приложения. Имейте в виду, если у вас завелся один фреймворк из стека Spring, то скоро все у вас будет на спринге, иначе вы замучаетесь все это увязывать. С одной стороны, хорошо — стандартизация же. А с другой — выглядит, как весьма некрасивый способ конкурировать.
- Spring становится все более монструозным. Изначально он делался как более простая и легкая альтернатива стеку Java EE. В результате получилось, что Java EE уже в разы проще.
Мои предложения по борьбе с гетерогенностью:
- Стандартизация используемого софта (включая сервера и библиотеки) на уровне всей системы. Как минимум, если все сервера обновлять в одно и то же время, масса проблем гетерогенности будут решены. Если же стандартизовать еще и используемые фреймворки — станет совсем хорошо.
- Фокусирование на этой проблеме внимания всего персонала, включая высшее руководство. Это задача, понятно, не для рядовых программистов, скорее — для той самой группы архитектурных решений, о которой я говорю с самого начала.
Интеграция
Проблемы интеграции сейчас рассматриваются как часть проблем гетерогенности, что в общем достаточно логично. Но есть несколько моментов, на которых я хотел бы остановиться отдельно в своих рекомендациях.
Запрет на интеграцию через общую базу. Последствия такой интеграции, думаю, ощутил на себе уже каждый Enterprise-разработчик. Сначала у вас все больше и больше приложений, интегрирующихся через одну и ту же базу, а потом вы уже не можете найти, кто использует конкретный столбец или даже целую таблицу, и поэтому вы не можете ее менять, а вынуждены дублировать информацию, чтобы что-то не развалилось. И вследствие этого — вынуждены писать данные и в старую таблицу, и в новую. А потом кто-то из программистов забывает записать в одну из таблиц, и данные в старой и новой схемах оказываются рассинхронизированы, и система, которая частично работает на старых данных, а частично на новых, вываливается в дикие ошибки, источник которых фиг найдешь. Я уж молчу, насколько разрастается структура базы данных, которая еще и не поддается никакому исправлению. В общем такая интеграция должна быть запрещена на уровне компании.
Стандартизация протоколов интеграции. Об этом я писал уже столько раз, что думаю пояснений не требуется.
Фокусирование на этой проблеме внимания всего персонала, в первую очередь — технического. Так как именно он часто принимает решения по этим вопросам.
Объемы данных
Нельзя сказать, что индустрия игнорирует запрос на обработку больших данных. Скорее наоборот: любой технический вызов является для индустрии своеобразным поводом для появления новых подходов и средств. А уж обрабатывать огромные массивы данных — это сама по себе весьма интересная техническая задача. Как вы знаете, все эти подходы выделились в отдельное направление Big Data, которое, естественно, сразу же стало новым золотым молотком. Ну кто бы удивился.
Раз есть решение для этой проблемы, бизнес тут же стал находить все больше и больше способов получать все больше и больше данных. Но об этом я говорил в прошлой статье.
Как у любого инструмента, у решений Big Data есть и свои проблемы:
- Внося в большую Enterprise-систему еще и решения на Big Data, мы увеличиваем что? Естественно, гетерогенность. Мы же не можем всю систему переписать на Big Data и не можем стандартными средствами работать с большими данными. Значит в наш зоопарк завезли нового бегемотика.
- И, естественно, добавляя новый массив решений, мы повышаем сложность всей системы.
Поймите меня правильно, я не против никаких решений. Тем более таких новых, красивых, блестящих, да еще и расширяющих наши возможности обработки данных, как Big Data. Я против бездумного использования чего бы то ни было. И я против того, чтобы в любом инструменте видеть Silver Bullet.
Кстати, о серебряной пуле, на роль которой в глазах многих новичков в программировании претендуют NoSQL базы данных. Но, как обычно, и тут не обошлось без проблем. Вкратце напомню:
- Как известно, любая база может обеспечить две из трех характеристик: скорость доступа, консистентность и распределенность. Так вот, если реляционные базы данных нам обеспечивают из коробки первые две (скорость доступа и консистентность), то нереляционные — первую и третью (скорость доступа и распределенность). И как вы понимаете, в определенных ситуациях (например, социальная сеть) выгоднее второе, а в Enterprise (где стоимость транзакции может быть и несколько миллионов долларов) — отсутствие консистентности из коробки — просто приговор. Так что каждый инструмент для своей задачи.
- И как обычно, добавление еще одного зверя в наш зоопарк явно не делает его меньше. В смысле гетерогенность опять растет.
Мои предложения по использованию технологий Big Data:
- Не каждая задача должна решаться на Big Data. Наоборот — на Big Data должны решаться только те задачи, которые ТОЛЬКО на ней и можно решить. Соответственно, на уровне системы должен быть определен список данных, с которыми мы будем работать инструментами Big Data. Эта часть должна быть четко инкапсулирована и защищена от всей остальной системы четко прописанным интерфейсом интеграции. Чтобы, не дай бог, другие части системы не лазали грязными руками в данные или вызывали не описанные в интерфейсе методы.
- Нужно для любых данных определить принцип устаревания, чтобы не хранились уже совершенно потерявшие актуальность терабайты не пойми чего, которые можно было заменить просто консолидированными данными. Тут полезно, наверное, вспомнить историю о том, как мы писали систему анализа посещений WAP сайта (да, это было очень давно). Так вот, вся аналитика, которую мы показывали, строилась на основе raw-данных. И делалось это чудовищно медленно, да еще плюс к этому данные забивали нашу реляционную базу. Слава богу, что в тот момент еще не было технологий Big Data, а то мы бы их безусловно использовали. Но это было давно, и мы были вынуждены пойти путем логики, а не грубой силы. И стали в результате вместо грязных данных хранить в базе консолидированные. Мало того, что мы теперь не забивали базу тоннами ненужных грязных данных, так и вся система начала работать практически мгновенно и перестала зависеть от времени накопления данных. К чему я все это? К тому, что иногда надо еще и пытаться обдумать задачу. А не бросаться решать ее в лоб, методом грубой силы.
Общие рекомендации
Итак, я думаю, наговорил уже на полный ящик гнилых помидоров. Но не могу себе отказать в удовольствии добавить еще пять копеек и поэтому выдам вам общие соображения, которыми я руководствовался для всех предыдущих рекомендаций.
Итак, это своеобразный манифест здравого смысла.
Коммуникации — важнее технологий
Весь мой опыт приучил меня, что если в разработке проблема, то крайне редко это технологическая проблема. Да, так, конечно, бывает, и это благословенный момент, когда программист может развернуться во всю мощь своих сил. Однако в большинстве случаев проблема лежит в плоскости передачи и обработки информации. И как мы знаем по правилу Парето — 20 % усилий дают 80 % результата. Сосредоточиться надо именно на этих проблемах, чтобы получить более существенное улучшение в целом. Если мы посмотрим на список основных причин провалов IT-проектов, то практически все они тем или иным способом относятся к коммуникации между людьми. Вот это и надо исправлять.
Архитектурные решения — важнее используемых средств
Честно говоря, принятие решения о используемом стеке технологий ДО того, как приняты хоть какие-нибудь архитектурные решения, бич современного Software Engineering. Самое неприятное, что, если мы возьмем список тем любой разработческой конференции, мы увидим темы «о новых возможностях фреймворка Х», «использование нового языка Y в ... системах» и «новое API библиотеки Z». Но никогда не увидим «сложные случаи декомпозиции предметной области» или «определение подходящей технологии под готовые архитектурные решения». И надо сказать, что ситуация эта возникла не на ровном месте. Если мы вспомним, например, сверхпопулярный сейчас стек технологий Spring, то увидим, что именно стек технологий диктует нам архитектуру, а не наоборот: мы сможем использовать его на уже построенной архитектуре. И это, по-моему, дорога в тупик.
Стандартизация — важнее идеального соответствия инструмента задаче
Да, я совершенно убежден, что в любой ситуации выбора надо выбирать то решение, которое уже используется в системе. Как говорится, лучшая дорога — та дорога, которую хорошо знает водитель. Чем более стандартизированными будут ваши решения, тем легче будет ваше приложение в поддержке и тем проще будет перекидывать разработчиков с проекта на проект. И уменьшение гетерогенности — вообще хорошая вещь. Конечно, вам может показаться, что есть риск попасть в плен однажды принятым и не лучшим решениям. Ну так на то мы и люди, чтобы определять золотую середину и следить за тем, что наше решение все еще достаточно хорошо для нас. Именно поэтому нас не так легко будет заменить роботами.
Напоследок небольшой дисклеймер: я ни в коей мере не претендую на универсальное знание. Тем более на то, что я знаю, как решить все проблемы. Эти статьи — просто описание того, что я лично вижу вокруг себя, и приглашение к разговору: давайте не замалчивать эти темы, а обсуждать их, а не «новые фичи фреймворка Х».
Удачи!