Как писать по-настоящему масштабируемый код?
Почему масштабировать вообще сложно?
Вавилонская башня вышла не особо масштабируемой
В сети много текстов, так или иначе касающихся масштабируемости кода, но авторы очень часто упускают одну главную вещь: почему масштабировать — это сложно.
Основная причина тут в том, что как только вы начинаете изменять какую-то большую систему, она начинает разваливаться. Ну, за исключением тех случаев, когда у вас вообще всё на 100% покрыто тестами. Однако, в реальном мире история с покрытием тестами такова, что код современных приложений покрыт (в лучшем случае) примерно на 1%.
Может быть, 100% покрытие тестами — это реальность не только для библиотек, утилит или компиляторов (ведь мы можем формализовать их поведение математически), но и для веб-приложения? Да не, фигня какая-то…
В общем, к тестам мы ещё вернемся, а пока давайте перейдем чуток на другой уровень абстракции. Главная проблема в том, что обратная связь насчет правильности, корректности кода должна быть молниеносной. В идеале вообще мгновенной. Покрытие тестами — это тоже один из видов обратной связи. Storybook — визуальное представление обратной связи, зачастую достаточное для того, чтобы вы могли быстро верхнеуровнево оценить корректность кода.
Есть еще один вид обратной связи — фидбек от ваших QA. Как вы понимаете, мгновенной ее назвать сложно, потому что как только вы вводите в процесс связь «человек <-> человек», вы порождаете бюрократию.
Ситуации со сложным масштабированием: примеры
#1 Интеграция неочевидной сторонней системы платежей
Допустим, вы работаете над приложением, в котором есть функции онлайн-платежей. Вам надо интегрироваться со сторонней платежной системой. У этой системы есть некое API, которое может работать только при развертывании вашего кода в облаке. А в облаке — ограниченное число серверов, так что вам надо еще и подождать в очереди.
Чтобы ждать в очереди, надо отправить запрос своему менеджеру. Вдобавок у вас есть фронтенд- и бэкенд-разработчики, которым надо нормально скооперироваться, чтобы без проблем развернуть всё на этом сервере.
Как вы понимаете, проблема может возникнуть на любом из участков описанной цепи, из-за чего весь процесс придется повторять. А ещё может возникнуть множество дополнительных вопросов по настройке, которые обычно и возникают в реальном мире.
Если бы для описанного API существовал прокси, который вы бы смогли настроить локально, и если бы можно было просто установить локально весь нужный стек, то вам было бы гораздо, гораздо проще решить задачу. Вы бы смогли написать набор тестов и запускать их каждый раз при внесении любых изменений, что существенно бы ускорило работу.
#2 Большая вымышленная вселенная
А вот пример вне мира компьютеров. Допустим, вы — популярный писатель, пишущий серию книг в жанре научной фантастики или фэнтези с обширной вселенной и лором (скажем, Властелин колец, Дюна, Звездные войны, в общем, подставьте любимую серию.). При написании вам нужно стремиться сохранить согласованность, чтобы ваша историю не рухнула под гнетом накопленных логических ошибок повествования и странных сюжетных ходов, которые понижают саму ценность истории.
Подобное, кстати, можно часто видеть в голливудских (да и не только) фильмах. Причина тут простая: чем сложнее становится история, тем сложнее отследить ее согласованность. А проверка корректности вообще не гарантирует правильности, а лишь увеличивает бюрократический эффект.
Будь у вас какой-то механизм, программа, которая могла бы быстро проверять согласованность, то вы бы смогли быстро получать обратную связь и активно продвигаться вперед в написани своей фантастической саги. В общем-то, такие механики уже существуют — например, инструменты на основе логики и прочее.
Польза мгновенной обратной связи
Плюсов тут множество, главный из которых (как мне кажется) — возможность отделить функциональные подсистемы и устранить ненужные DevOps- и бизнес-процессы, а также узкие места. Давайте немного подробнее про каждый пункт.
Отделение функциональных подсистем
Когда у вас есть достаточное покрытие тестами, вы можете рефакторить части кода, дабы сделать их менее взаимозависимыми, а также чаще их переиспользовать. Но это должно происходить только как следствие наличия у вас мгновенной обратной связи о корректности работы, а не из-за заранее продуманной архитектуры. Потому что даже если вы заранее продумали свою архитектуру и сделали это хорошо, она все равно будет подвержена проблемам масштабируемости (что отсылает нас к примеру про вымышленную вселенную).
Мгновенная обратная связь дарит вам возможность использовать принцип «разделяй и властвуй» — будет гораздо проще разбить систему на подсистемы, которыми вы сможете управлять отдельно, не затрагивая остальные ее части.
Устранение ненужных процессов DevOps- и бизнес-процессов, а также узких мест
Так как наличие мгновенной обратной связи означает, что у вас будет правильно работающая система, вы устраняете необходимость создавать дополнительные «бюрократические» шаги от разработки до продукции.
Что в итоге
Надеюсь, у меня получилось продемонстрировать, что для создания масштабируемого продукта вам необходима мгновенная обратная связь о корректности его работы. Помните, что она возможна только в условиях отсутствия бюрократии.
Всё это подводит нас к другому вопросу — как достичь 100% покрытия тестами в приложениях в реальном мире?