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

По сути, мы с моей командой унаследовали монолит Groovy on Grails, лихорадочно создаваемый за границей только под надзором со стороны нетехнической управленческой команды. Срок выполнения любой функции или даже исправления ошибки составлял минимум 4 недели, чтобы довести функциональность до производственной среды (1 неделя + 2-недельный спринт + 1 неделя QA). Грубо для «стартапа».

На высоком уровне наше приложение представляет собой «платформу найма» для найма почасовых сотрудников в ресторан и розничную торговлю, которая состоит из следующих

  1. Соискатель работы / потребительское заявление о приеме на работу
  2. Панель управления работодателем / предприятием для управления кандидатами

Web MVC Framework для корпоративного приложения: Grails / JSP → React.js

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

Мы поняли, что микросервисы на самом деле означают макросервисы и что попытки разбить приложения на более мелкие часто не окупаются накладными расходами, например, при совместном использовании CSS. Но приложение работодателя / предприятия было настолько отделено по функциональности от стороны соискателя / потребителя, что имеет смысл разделить линию на отдельные микросервисы.

Я большой поклонник статьи Выбирайте скучную технологию и сомневался, какой стек выбрать, тем более, что мы превращались в Angular House. Один из наших разработчиков Angular привел конкретные причины для перехода на Angular 2 (улучшенная инъекция зависимостей, компоненты не должны взаимодействовать с DOM или виртуальной DOM и т. Д.), Но все они казались достижимыми в React.js. Больше всего меня беспокоило React.js: 1) отсутствие рецепта (соглашение важнее конфигурации) и 2) добавление еще одного стека.

После того, как я попробовал Angular 1.x сам (как технический директор высокого уровня), я обнаружил, что процесс обучения был довольно трудным, особенно потому, что код был чистым Javascript и включал в себя тонны трудных для чтения «передачи функций». В то время ES6, JSX и Typescript не рассматривались.

После прослушивания подкаста я понял, что React.js можно легко внедрить в любую устаревшую кодовую базу, поскольку React позже состоял только из представления (модели и контроллеры MVC не требовались). Для запуска представления приложения React.js нужно просто создать приложение локально, загрузить связанный javascript (bundle.js) в CDN, например Amazon S3, и сослаться на него из приложения Grails, как показано ниже:

<link href="https://s3.amazonaws.com/react-apploi/main.css" rel="stylesheet">
<div id="root"></div>
<script type="text/javascript" src="https://s3.amazonaws.com/react-apploi/bundle.js"></script>

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

Я также понял, что Redux (широко используемое глобальное хранилище состояний) также можно легко внедрить, поскольку он также был чистым Javascript. Эта презентация помогла мне понять необходимость Redux.

Обмен сообщениями:

СТАРАЯ: ActiveMQ

НОВИНКА: Python MRQ

Вместо того, чтобы продолжать размещать наш собственный сервер ActiveMQ, мы выбрали mrq, в основном из-за красивой панели управления, RESTful HTTP (вместо AMQP) и их поддержки «очередей ошибок», которые могут хранить неудачные события для восстановления с помощью периодического опроса. Мы подумали о классическом решении «купить против сборки», в котором мы чувствовали, что природа сторонних решений, таких как Iron.io, была зрелой, цены были низкими, а риск был минимальным, чтобы полагаться на них. mrq требовал MongoDB и Redis на бэкэнде, которые мы хотели бы поддерживать, но мы пошли с размещенными версиями, чтобы минимизировать накладные расходы и максимизировать надежность. Это того стоило из-за мощи панели инструментов mrq, которая позволяет осуществлять мощный мониторинг очередей, заданий и рабочих, показывая статус всего и позволяет легко повторить попытку.

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

API:

СТАРЫЙ: Grails

НОВИНКА: Python + Flask + Swagger

Обычно проблема разрушения монолита влечет за собой централизованное хранилище данных с API, и мы следовали той же парадигме. Мы по умолчанию использовали комбинацию Python + + Flask + SQLAlchemy из-за успеха, который я испытал во время работы или кампании Обамы для Америки в 2012 году. SQLAlchemy - чрезвычайно универсальная ORM (скоро появятся примеры). Мы соединяем его с Alembic в качестве нашей библиотеки миграции (которая подключается к Flask с помощью Flask-Migrate), что нам нравится, потому что миграции могут быть созданы автоматически путем 1) обновления модели и 2) запуска сценария. Ненавижу ручное создание миграций. Одним из ключевых отличий нашего API является то, что проверка данных выполняется путем синтаксического анализа документации Swagger с помощью декоратора Python.

  • MarshmellowObject - валидатор и сериализатор
  • Monkeypatch - для имитации методов, таких как вызовы API (requests.get)

ORM

СТАРАЯ: MySQL RDS

НОВИНКА: MySQL RDS + SQL Alchemy + Alembic

Приятная особенность Alembic заключается в том, что он автоматически обнаруживает изменения в модели и генерирует миграцию.

SEO:

СТАРЫЙ: Grails

НОВИНКА: Prerender.io

Обмен ссылками на вакансии был критически важен для нашего бизнеса, чтобы стимулировать их внедрение в розничных магазинах и ресторанах, но размещение ссылки на Facebook, например, отображало ссылку без каких-либо метадет, таких как заголовок страницы, описание и изображения, поскольку SPA обслуживают javascript и браузер отображает окончательный HTML. К счастью, Google достаточно сложен, чтобы выполнить Javascript перед индексированием вашей страницы в их поиске, но, поскольку большинство из них не настолько сложны, мы использовали сторонний сканер Prerender.io для предварительного рендеринга всех наших общедоступных страниц, на которых размещается кешированный статический HTML. который, как естественный побочный продукт, поддерживает SEO. Плата за предварительную визуализацию зависит от страницы и ее актуальности (1–30 дней) в кеше. Установка была чрезвычайно простой: установили пакет Node.js, настроили новое приложение Express.js (показано ниже), которое обнаруживает краулер поисковой системы в заголовке HTTP и перенаправляет запрос на серверы prerender.io.

if (env === 'prod' || env === 'staging') {
  var prerender = require('prerender-node')
  .blacklisted([
    '/view/a.*',  // don't waste $ pre-rendering aggregated jobs
  ])
  .set('prerenderToken', 'blahtokenblah')
  .set('protocol', 'https');
app.use(prerender);
}

Отчетность: Grails → Mode Analytics

Отчетность, даже внутренняя, была построена как «функция» в базе кода с использованием запросов Hibernate и страниц сервера Grails. К счастью для нас, совместные веб-инструменты были готовы к прайм-тайм, включая платформы, ориентированные на SQL, такие как Civis Analytics, Mode Analytics и Periscope. Мы хотели избежать необходимости в специальном аналитике данных, который должен был бы изучать тонкости мощной аналитической платформы, такой как Tableau и Looker, которые требуют языка моделирования и становятся дорогостоящими в обслуживании. Мы выбрали режим среди других в основном из-за модели ценообразования «начать с малого», 100% чистого SQL-фреймворка и удобного взаимодействия с пользователем (простая совместная работа при редактировании запросов, поток активности, несколько запросов на отчет, организация запросов в списки) . Мы были довольны добавлением более мощного инструмента визуализации в будущем, но часто испытывали боль при составлении отчетов о воронках с помощью SQL.

Хранилище данных

СТАРЫЙ: MySQL OLTP

НОВИНКА: Segment.io + Amazon Redshift + dbt.

У нас не было никакого представления о хранилище данных, кроме реплики сервера RDS, с которой столкнулся Grails. Реплика не вызвала никаких проблем, но у нас была серьезная потребность в отслеживании поведения пользователей с помощью событий в духе MixPanel, Kiss Metrics и Google Analytics. К сожалению, для всех этих инструментов требуется собственное запатентованное хранилище данных, что приводит к большим расходам (даже с GA, учетная запись «Премиум» необходима для экспорта данных для выполнения более сегментированных запросов)

Segment.io - это хранилище данных общего назначения, которое можно использовать с любым инструментом отчетности. Это приятно, потому что они включают оболочки, которые автоматически отправляют события в другие службы, в том числе в Google Analytics и Intercom.io. Они позволяют нам управлять нашим собственным экземпляром Redshift и взимать плату по MTU (ежемесячно отслеживаемое количество пользователей), поэтому счет соответствует фактическому росту пользователей. Пользовательский интерфейс великолепен, и есть хороший отладчик, который помогает подтверждать события, отправляемые в хранилище данных в режиме реального времени.

Самое приятное то, что мы можем использовать хранилище данных Segment с любыми инструментами отчетности, которые нам нужны, в нашем случае Mode Analytics и Sisense. Наши простые SQL-запросы написаны, смоделированы, проверены и протестированы в среде под названием https://www.getdbt.com/, поэтому мы не связаны с инструментом бизнес-аналитики или инструментом отчетности. Это

DNS и сокращение ссылок

СТАРЫЙ: GoDaddy + DigiCert + bit.ly

НОВИНКА: ребрендинг + CloudFlare

Мы решили перейти с bit.ly, потому что приоритеты продаж там требовали минимум 1000 долларов в месяц, и обнаружили Rebrandly через мой любимый сайт поиска приложений / инструментов: Product Hunt. В то время Rebrandly взимал плату за аналитику, а не за количество укороченных ссылок.

Мы зарегистрировали наш домен сокращения ссылок (http://apploi.link) в Rebrandly, и они нашли способ использовать CloudFlare для поддержки соединений SSL https без необходимости покупать сертификат SSL у нашего провайдера DigiCert. Хотя я нашел техническую поддержку DigiCert очень полезной, я нашел поддержку Rebrandly исключительной. CloudFlare автоматически сканирует наши записи DNS и предоставляет нам несколько адресов серверов имен для предоставления нашему регистратору (Rebrandly).

Отслеживание ссылок

(Хаос) → Владелец Data Analyst + менеджмент utm

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

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

  1. utm_source: facebook, email_newsletter, smarter-chaos, craigslist
  2. utm_medium: социальные сети, электронная почта, партнерская программа, доска объявлений (по существу категория высокого уровня для utm_source)
  3. utm_term: соискатель, розничная торговля, почасово (ключевые слова adword)
  4. utm_content: split-test-A, split-test-B (для тестирования A / B, когда ссылка указывает на тот же URL)
  5. utm_campaign: 2016-сезонный найм (продвижение высокого уровня)

Развертывания:

СТАРЫЙ СТЕК: Bitbucket + Jenkins + AWS + Hipchat

НОВЫЙ СТЕК: Github + Heroku + Travis + SauceLabs + Slack

Частично основываясь на успешном масштабировании Upworthy с помощью Heroku, даже в качестве одного из сайтов с наибольшим трафиком в стране, мы решили ограничить наши усилия по DevOps. Как стартап, бюджет на штатного DevOps-инженера не имеет смысла, а хороших тех, кто работает неполный рабочий день, чертовски невозможно найти. Еще одна причина, по которой мы выбрали Heroku, заключается в том, что мы большие поклонники их «приложений для обзора», которые автоматически развертывают временный сервер, когда вы создаете запрос на вытягивание (а не ветку) на Github, который запускает код для развернутой на нем ветки запроса на вытягивание. . Это позволяет разработчикам быстро тестировать, особенно при сотрудничестве с нашим инженером по эксплуатации.

Качество кода: (ничего) ⟶ Pull requests + Code Climate

Мы упрощаем проверку кода, публикуя пулреквест в канале Slack под названием #tech_pull requests. Я лично ненавижу отвлекать разработчиков (или кого-либо еще в этом отношении), поэтому мы настоятельно рекомендуем использовать функцию напоминаний Slack, чтобы избежать перерыва в концентрации.

Что касается стандартов кодирования, мы настоятельно рекомендуем понятие умной фиксации, означающее, что одна фиксация должна включать только одну функцию или цель и может быть проверена в течение 5 минут. Я лично использую функцию построчной фиксации в приложении Github Desktop для индивидуального выбора конкретных строк для фиксации. Более того, мы не поощряем комментирование в целом (недавно наткнулся на Хороший код - это лучшая документация) вместо ясных и кратких сообщений о фиксации и постоянно используем git blame в качестве комментариев.

Кодирование видео (Zencoder → Ziggeo)