На хабре Rider уже неоднократно упоминался, но дабы дать нашим читателям взглянуть на процесс разработки «изнутри», при этом поняв специфику процесса на разных этапах производства, мы обратились в JetBrains, и на наши вопросы ответили:
- Кирилл Скрыган, тимлид проекта Rider и старший разработчик;
- Дмитрий Иванов, главный разработчик протокола реактивного многопроцессного взаимодействия в Rider;
- Андрей Акиньшин, серебряный призёр ACM ICPC, в Rider отвечает за NuGet-менеджер.
За какую часть проекта Rider вы отвечаете? Какие задачи перед вами поставлены?
Кирилл Скрыган:
Я — тимлид проекта Rider. В мои задачи входит планирование задач, координация всей команды, и отчасти, дизайн продукта. Помимо этого, я много программирую, отвечаю за синхронизацию текстов, редакторов, code completion, и кучу второстепенных, более мелких задач.
Дмитрий Иванов:
Я занимаюсь реактивным протоколом передачи данных между Java и .NET.
Андрей Акиньшин:
В Райдере очень много частей и все они тесно связаны друг с другом. Как правило, за каждую подсистему у нас есть ответственный человек. Но на практике помимо своей зоны ответственности приходится активно взаимодействовать с командой и помогать дорабатывать другие подсистемы. Я сейчас активно занимаюсь NuGet-менеджером и поддержкой юнит-тестов.
Что оказалось самым сложным в реализации с технической точки зрения?
Кирилл Скрыган:
Взаимодействие фронтэнда и бекэнда должно быть консистентным, но при этом быстрым. Можно, конечно, все данные прогонять через главные потоки процессов — но вот будет ли это быстро? Поэтому мы и перешли к модели, где два процесса реактивно взаимодействуют друг с другом в многопоточном режиме. Мне кажется, решение всех возникших при реализации этого процесса проблем и было наиболее сложной задачей.
При проектировании Rider мы закладываемся на важный инвариант: фронтэнд может присоедениться к уже работающему бекенду, в любой момент времени — и наоборот. Это дает потенциальные функциональные преимущества: например, возможность при работающем фронтэнде перезапускать бэкенд, если в нем произошло нечто фатальное. Однако главное, что дает этот подход — это удобство написания консистентно работающего кода. Ведь без этого инварианта, то есть без сохранения состояния бэкенда и фронтэнда, взаимодействие сводилось бы к банальной request — responce архитектуре. В случае со сложной многопоточной IDE это приводило бы к кучам лишних проверок в коде, в духе «а могу ли я сейчас принять этот request — или подождать пока у меня тут все загрузится и сказать бекенду отправить мне сообщение, которое я уже смогу принять?»
Учитывая, что у нас и фронтэнд и бекенд — это сложные многопоточные процессы, такой подход был бы прямой дорогой в ад рейсов и дедлоков. В итоге, мы пришли к модели, где у нас есть реактивное и изменяемое состояние модели, распространяемой на обе стороны протокола, на оба процесса. Получилось что-то вроде MVVM архитектуры. «Вроде» сугубо потому, что нам все же без транзиентных пересылок больших данных не обойтись. Возможно, если бы у нас не было такого мощного фронтэнда как Intellij Platform, наш MVVM был бы более чистым.
Дмитрий Иванов:
Получить здоровую Threading-модель в многопроцессном приложения. Представьте, у нас есть две кодовых базы — Intellij Idea и ReSharper, у каждой из которых есть своё понимание как жить в многопоточном окружении, свои локи, свой главный тред с управляемой reentrancy и т.д. Плюс к этому — несколько дополнительных процессов: msbuild tasks, debuggers. И теперь надо со всем этим «взлететь», плюс получить свободную от лагов и не разваливающуюся по швам среду.
В самом первом прототипе — когда он ещё даже и не назывался Rider — мы использовали Google Protobuf, и строили работу на основе обычного RPC. Довольно быстро пришло осознание, что «Идею» мы хотим использовать как View, а взаимодействие построить по принципу MMVM. В .NET-мире мы привыкли к реактивному XAML, и строить UI по другим принципам, которые мы считаем устаревшими, не хотелось. Возник вопрос — как заставить джавовый Swing встать на реактивные, межпроцессные, да ещё и кроссплатформенные рельсы? Как это часто бывает в JetBrains, ни одно из существующих решений нам не подошло, и мы стали разрабатывать своё.
Теперь ViewModel описывается в очень краткой форме с помощью возможностей DSL, предоставляемых Kotlin. Из модели генерируются реальные Java и C# классы, синхронизируемые между процессами. Любое изменение модели, что с одной, что с другой стороны порождает реакцию.
Скоро выяснилось, что в рамках честной ViewModel, в силу ограничений UI-контролов и сложности программирования, мы удержаться не можем, и пришлось для некоторых фич передавать данные целиком — например, Code Completion может передать все свои 50 тысяч элементов. Очень помогло, что мы сразу делали протокол бинарным и оптимизированным (привет всем противникам преждевременной оптимизации =). В общем, в производительность протокола мы нигде не втыкаемся. Моё мнение, что, по показателю «удобство\скорость» мы попали в десятку, решив выбрать именно такое техническое решение.
Андрей Акиньшин:
Сложно выделить какую-то одну самую сложную часть. Задачи стоят самые разные, каждая сложна по-своему, каждый день приходится сталкиваться с новыми сложностями. Скажем, сегодня разбираешься с устройством каких-нибудь подсистем в R# и IDEA, завтра пытаешься спроектировать реактивно-асинхронную модель, которая позволит этим подсистемам дружить (и делать это быстро и отзывчиво), а послезавтра пытаешься понять отчего же у тебя под вот такой вот версией Linux ничего не работает.
Какие проблемы возникли при разработке версий для Linux? MacOS?
Кирилл Скрыган:
Под Linux и MacOS на данный момент код бэкенда исполняется на Mono. Главной задачей было переписать код проекта так, чтобы он под Mono запускался в принципе, а также поправить всю соответствующую инфраструктуру проекта под это. Помимо этого, мы регулярно сталкиваемся с разного рода специфичными багами Mono, поиск и отладку которых приятным процессом не назовёшь.
Банальные отсутствия проверок на null в определённых случаях приводили к полному крашу бекенда. До безобразия просто и медленно в Mono написан I/O код, который, к примеру, без всякого мерджа держал открытый FileSystemTracker handle на каждый запрос (и тут мы сразу же передаём привет OutOfMemory и неочевидным проблемам с производительностью). Начиная с каких-то версий, в Mono перестали подкладывать таргеты для веб проектов. Отдельного слова заслуживает xbuild, API которого работают весьма «творчески», что в особенности касается модификации проектной модели. Что-то из этого мы фиксим в самомо коде Mono, поставляя свои патчи, что-то обходим своими средствами. И все же в целом, могу сказать, что приятно удивлен качеством работы Моно. Да есть баги, но в целом, все как-то работает, и даже более или менее стабильно на разных платформах — я лично ожидал худшего.
Дмитрий Иванов:
Возникали и возникают проблемы с Mono. Например, в версии 4.4 у нас стали зависать сокеты — оказалось, что баг. Всё-таки .NET Framework гораздо стабильнее. Но мы не жалуемся — шлём патчи =)
Андрей Акиньшин:
Сперва решались проблемы по запуску R# на Mono (пришлось выпиливать зависимости на WPF и COM, переделывать unsafe-магию, править баги в самом Mono и т.п.). Потом мы решали платформо-специфичные проблемы (например \r\n в R# vs \n в Idea; взаимодействие с файловой системой и всё такое). Сейчас мы активно стараемся доработать кроссплатформенные стеки разработки (например, научиться хорошо дружить с XBuild).
Отличается ли функционал IDE под разными ОС? Если да, то в чём?
Кирилл Скрыган:
Нет, практически ни в чем не отличается. По крайней мере, не должен :)
Дмитрий Иванов:
Мы стараемся, чтобы User Experience не отличался в разных операционках. Ну разве что билдсистемы используются разные.
Андрей Акиньшин:
Наша задача сделать так, чтобы функционал ни в чем не отличался. Порой всё идёт не так гладко, как хотелось бы, но, думаю, к версии 1.0 мы справимся.
Что из функционала Rider, по вашему мнению, является killer feature, если сравнивать Rider с MSVS?
Кирилл Скрыган:
Во-первых, просто на порядок более мощный функционал во всех направлениях. В десятки раз больше навигаций, анализов кода и рефакторингов (quick fixes, intentions, context actions), Solution Wide Analysis, unit-test runner, великолепная поддержка практически всех VCS, и еще множество решарп-фич, которые успешно создавались последние 10 лет. Да, мы пока еще не все успели «синхронизировать», но не вижу никаких причин, почему мы этого не сможем сделать в ближайшее время. Помимо всего прочего, у Rider отличная поддержка не только C#, но и многих других языков: JavaScript, TypeScript, HTML, CSS, Razor, VB.NET, Regex, и многих других.
Во-вторых — это конечно сложно назвать функционалом, но уже сейчас многие наши пользователи отмечают очень высокую скорость работы Rider. И это ещё до того, как мы начали активную фазу оптимизации проекта. Вполне возможно, что дело в том, что у нас нет внутри 20-летнего COM’a :).
Попробуйте в Visual Studio при открытом более или менее большом проекте, сделать git pull, который обновит .csproj файлы — после этого можно смело идти пить чай на полчаса. Всему виной код самой Visual Studio, которые как-то неправильно перезапускает MSBuild для изменившихся проектов. Вообще, за 5 лет работы в Resharper, я многого навидался в коде VS, например GC.Collect(), вызываемый в цикле :) В этом смысле мы чувствуем себя на порядок свободнее при написании полностью своей IDE.
Дмитрий Иванов:
Самое главное, на мой взгляд — это наличие у нас всех основных фич Resharper, и при этом — отсутствие лагов. По-моему, этого более чем достаточно.
Андрей Акиньшин:
Если уйти от сравнения с Visual Studio, то моя любимая фича в Rider — консоль, встроенная в IDE. Это просто прекрасно, я каждый день запускаю какие-нибудь консольные приложения и радуюсь.
Какой вы видите сферу применения Rider уже сегодня?
Кирилл Скрыган:
Работа со всеми теми проектами, с которыми вы работали в Visual Studio, а также разработка кросс-плафторменных мобильных приложений под MacOS, Linux — то есть Rider вполне может заменить Xamarin Studio и Mono Develop. Большая часть команды разработки программирует Rider в нём же самом :)
Дмитрий Иванов:
В JetBrains догфудинг — одна из основных практик разработки. Мы используем Rider для разработки Rider. Немотря на нестабильность, уже сейчас писать в Rider IDE с его гладким тайпингом — это удовольствие.
Андрей Акиньшин:
Главным образом, это кроссплатформенная .NET-разработка. Если вы любите Linux или MacOS, но при этом хотите писать на C# в очень крутой полнофункциональной IDE, то Rider — ваш выбор.
Вы уже собрались в Санкт-Петербург? Ведь мы по-прежнему ждём вас 3 июня на конференции DotNext 2016 Piter, на которой будут крутые доклады о Rider:
Кирилл Скрыган — Rider — новая кросс-платформенная .NET IDE от JetBrains. Что это такое и как это работает.
Дмитрий Иванов — Реактивное многопроцессное взаимодействие: JetBrains Rider Framework.
А третий участник нашего интервью выступит с хардкорным докладом… про арифметику (на самом деле, не всё так просто):
Андрей Акиньшин — Поговорим про арифметику
Будут и другие доклады. Так что берите футболку, пиджак, куртку, свитер — и в Питер. Кто знает, как изменится погода за день.
Комментарии (0)