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

Наше путешествие разбито на 6 шагов:

  1. 📍 Наша отправная точка - «устаревший» опыт программирования и его ограничения.
  2. 🗺️ Выбор направления - как выглядит новый опыт программирования?
  3. 📝 Планирование нашего маршрута - как мы доберемся до места назначения?
  4. 🛫 Bon voyage - окунуться в само путешествие
  5. 🛬 Финальный подход - поэтапное знакомство с нашим новым опытом
  6. 🏖️ Прибытие к месту назначения - размышления о том, где мы приземлились, и наших дальнейших шагах.

📍 Наша отправная точка

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

Отправной точкой нашего путешествия является пользовательский редактор кода, построенный на основе библиотеки Ace Editor. Этот редактор служил надежной основой Campus - нашего интерактивного приложения курса - в течение нескольких лет. Со временем ограничения нашей существующей реализации начали проявляться:

  • Плохая доступность: мы хотели сделать наш кодинг еще более доступным. Этого было трудно достичь с нашей текущей реализацией из-за основы, на которой она была построена. Помимо других проблем, он страдает от «ловушки клавиатуры» - фокус клавиатуры будет поглощен редактором, и от него практически невозможно будет убежать - это было серьезным ограничением для пользователей, которые используют программы чтения с экрана и перемещаются с помощью клавиатуры.
  • Плохая абстракция: из-за того, как он был изначально реализован, в сочетании с «гниением кода» на протяжении многих лет старый редактор был плохо абстрагирован, и было трудно понять, где его границы находятся в нашем приложении. Проще говоря, код был разбросан по разным местам, и его трудно было рассуждать. Из-за этого нам было сложно поддерживать и создавать новые функции для
  • Технологический тупик: он был построен на основе зрелой, но «старой школы» библиотеки редактирования кода из более раннего поколения библиотек JavaScript, которые больше не видят особых препятствий для активной разработки - ограничивая будущие улучшения пользовательского опыта
  • Низкая производительность страницы. Из-за размытых границ компонентов нам было трудно найти подходящий «шов» для разделения пакета кода. Это означало, что он был включен в основной пакет JavaScript нашего приложения независимо от типа упражнений, которые выполнял пользователь, что в конечном итоге замедлило его работу.

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

️🗺️ Выбор направления

Помня о проблемах нашей предыдущей реализации, мы начали мечтать о том, как будет выглядеть наш идеальный пункт назначения:

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

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

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

Попутно мы оценили несколько решений, но в конечном итоге остановились на создании нашего опыта редактирования поверх Монако. Некоторые из вас могут знать Монако как солнечный микрогосударство, принимающее Гран-при на Французской Ривьере, но это также редактор с открытым исходным кодом, который поддерживает Visual Studio Code, чрезвычайно популярную и хорошо поддерживаемую интегрированную среду разработки.

Наши причины выбрать Монако включают, но не ограничиваются:

  • Значительно улучшенная встроенная поддержка специальных возможностей
  • Более современный интерфейс редактирования для наших пользователей и более современный API, с которым мы можем работать, вокруг которого мы можем построить простую абстракцию.
  • Он поддерживается как Microsoft, так и является проектом с открытым исходным кодом и, вероятно, будет разработан в обозримом будущем.
  • Он модульный и позволяет нам отправлять только те части и детали, которые нам нужны для работы с DataCamp.

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

📝 Планирование нашего маршрута

Несмотря на то, что он проделал большую работу по обеспечению опыта кодирования DataCamp, с нашей существующей реализацией редактора кода было трудно работать, потому что она не была хорошо инкапсулирована:

  • Он был разделен на несколько разных пакетов в разных репозиториях. Это добавило когнитивных накладных расходов на понимание того, как это работает, а также добавило трения к опыту разработчиков.
  • Это тоже была «дырявая абстракция». Хотя он был абстрактным, по всему хост-приложению были также разбросаны небольшие фрагменты кода, CSS и дублирования, что затрудняло поиск истинного «стыка» или границы, за которой фактически находится модуль.

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

Для нашей новой реализации мы остановились на простейшей абстракции, которую мы могли бы использовать в этом сценарии: компоненте React, который мы могли бы добавить в нашу кодовую базу с несколькими реквизитами, необходимыми для взаимодействия с хост-приложением:

Возможность интеграции нашего редактора в Campus с относительно небольшим количеством строк кода упростила его сосуществование с существующими функциями редактора. Как упоминалось ранее, мы стремимся создавать новый редактор постепенно и избегать «большого взрыва» перезаписи / выпуска, а наличие хорошо инкапсулированного компонента сделало довольно тривиальным обернуть путь кода с помощью флага функции, который позволил бы нам динамически переключаться включение / выключение новых функций для конкретных пользователей или определенного процента нашей пользовательской базы (о чем мы поговорим позже!).

Теперь, когда наш маршрут спланирован, мы можем отправиться в наше великое путешествие!

🛫 Bon voyage

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

В DataCamp мы пишем большую часть нашего внешнего кода на React. Чтобы сделать работу с Monaco более удобной, мы использовали простую оболочку response-monaco-editor, которая позволяет Monaco более легко выполнять рендеринг в качестве компонента React.

Мы загружаем сам пакет кода редактора с помощью monaco-editor-webpack-plugin: это дает нам больше контроля над составлением пакета редактора и позволяет нам выбирать различные элементы Monaco, которые нам нужны. Например, выберите только ту языковую поддержку, которую мы фактически используем в наших курсах, например Python или R. Загружая поддержку только для определенных языков и функций, мы можем уменьшить размер пакета, что означает, что он будет загружаться быстрее в браузерах наших пользователей. .

Хотя большая часть тяжелой работы с редактором выполняется самим Monaco, у нас также есть большое количество настраиваемой логики, которая необходима для интерактивного программирования DataCamp:

  • Пользовательские сочетания клавиш и поведение: например, Shift + Return выполнит текущую строку и переместит курсор на следующую строку
  • Пользовательское выделение ошибок: когда вы отправляете упражнение на DataCamp, серверная часть может возвращать местоположение кода, которое мы затем можем использовать для отображения ошибки.
  • Пользовательская раскраска синтаксиса: окончательная версия нового интерфейса редактирования будет отправлена ​​в рамках обновления нашего бренда в 2020 году, поэтому все должно выглядеть соответствующим образом.
  • Настраиваемое поведение автозаполнения: предложения кода, которые вы видите при редактировании кода в DataCamp, выводятся как путем токенизации кода упражнения, так и путем выполнения команд на нашем сервере.
  • Удаление различных функций Monaco, которые не требуются в нашем опыте редактирования, например, встроенной палитры команд.

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

К сожалению, нам иногда приходилось использовать «хаки» или обходные пути, необходимые для реализации некоторой настраиваемой логики. Однако мы сводим их к минимуму и документируем, когда они требуются.

Есть еще один аспект программирования DataCamp, о котором мы еще не упомянули: интерактивная консоль. Консоль - это то место, где пользователи могут вводить специальные команды / код и видеть результат в прокручиваемом буфере.

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

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

Мы построили наш новый компонент редактора кода постепенно, в течение пары спринтов (обычно мы используем двухнедельные спринты), и, используя флаг функции, мы смогли предоставить функциональность постепенно и итеративно, о чем мы говорим больше, когда начинаем наш окончательный подход. в Монако!

🛩️ Финальный подход

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

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

  1. Сначала мы отправили эту функцию внутри компании, чтобы собрать отзывы сотрудников.
  2. Затем мы расширили нашу пользовательскую базу до 10% и увеличивали ее еще на 10–20% каждую неделю, поскольку наша уверенность в новой реализации увеличивалась.

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

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

Окончательное 100% развертывание нового интерфейса редактирования было скоординировано, чтобы произойти одновременно с обновлением бренда в масштабах всей платформы в 2020 году. В октябре 2020 года мы наконец щелкнули выключателем, и новый опыт программирования стал доступен для всей нашей пользовательской базы!

Однако оставалось сделать еще один последний шаг. Из-за проведенного нами инкрементального развертывания основная кодовая база Campus по существу содержала два полноценных редактора кода бок о бок: устаревший интерфейс, получающий 0% трафика, и новый интерфейс, получающий 100%. Последним шагом было просто удалить старый редактор и все пути его кода из нашей кодовой базы!

🏖️ Посадка в пункте назначения

Это был долгий путь, но мы наконец-то прибыли в солнечное место! Море теплое, а пина колада прохладная. Давайте подробнее рассмотрим, где именно мы приземлились. Но сначала давайте быстро поразмышляем о том, с чего мы начали:

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

В отличие от того, где мы сейчас находимся:

  • Более простая кодовая база, которая хорошо абстрагирована и проста в обслуживании.
  • Построенная на базе Monaco, более современная и активно развивающаяся библиотека редактирования.
  • Значительно улучшенные специальные возможности - и отсутствие ловушки клавиатуры (Ctrl + Shift + M на Mac, Ctrl + Shift в Windows / Linux)!
  • В качестве бонуса может загружаться асинхронно из-за четкой границы абстракции, которая помогает нам управлять производительностью.
  • Лучший опыт для наших пользователей!

🕶️ Глаза на горизонте

Давайте взглянем на некоторые важные выводы из нашего великого путешествия и заглянем в будущее.

Подберите правильную абстракцию

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

Агрессивно снижайте сложность

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

Встаньте на плечи гигантов

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

Создавайте и доставляйте поэтапно

Один из ключевых принципов Agile - постепенное создание и поставка, и этот проект не стал исключением. Избежание выпуска «большого взрыва» позволило нам постепенно увеличивать ценность, учитывать отзывы наших клиентов и, в конечном итоге, снизить риск изменения одного из самых фундаментальных аспектов опыта кодирования DataCamp.

💭 Заключительные мысли

Хотя мы находимся в лучшем месте по сравнению с тем, с чего начали, наше путешествие еще не закончено. Мы заложили основу для успеха, но впереди еще много работы:

  • Monaco - чрезвычайно удобная платформа для развития: хотя мы многое получаем бесплатно, мы еще не начали извлекать все выгоды за счет инноваций в основном пользовательском интерфейсе нашего редактора.
  • Мы улучшили доступность интерфейса редактирования кода, но есть еще много вещей, которые мы могли бы сделать лучше и будем продолжать делать это в будущем, не только в рамках наших курсов, но и на всей платформе DataCamp.
  • В этом году мы внимательно изучаем производительность, и не избежать того, что Monaco - это большая библиотека, которую можно отправить в браузер. Это особенно важно для наших клиентов в развивающихся странах, где производительность и пропускная способность ограничены. Мы лишь слегка коснулись улучшений, которые мы можем внести в объем кода, который мы отправляем, и будем работать над этим в ближайшие недели и месяцы.
  • Из-за необходимости поддержки очень старых браузеров мы основываемся на более старой версии редактора Monaco. Недавно мы прекратили поддержку некоторых старых браузеров, что означает, что теперь мы можем использовать последние версии Monaco.

В целом, мы довольны тем, как прошел этот проект, и извлекли ценные уроки о замене ключевой части опыта обучения DataCamp с минимальными помехами для наших учащихся. Надеемся, вам понравилась поездка!

Кстати, нанимаем! Есть много открытых вакансий во многих отделах, включая Data Science и Engineering. Приходите посмотреть, мы с нетерпением ждем встречи с вами!