В начале января JetBrains объявили о разработке Rider, кроссплатформенной IDE на основе ReSharper и платформы IntelliJ, доступной под Windows, Linux и Mac OS X, и включающей в себя все фишки ReSharper, и поддерживающей .NET Framework, Mono и CoreCLR. Предполагается, что разработка будет завершена к осени этого года, а все желающие смогут попробовать среду «на зубок» в рамках Early Access Program.
На хабре 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 и т.п.). Потом мы решали платформо-специфичные проблемы (например rn в 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.
А третий участник нашего интервью выступит с хардкорным докладом… про арифметику (на самом деле, не всё так просто):
- Андрей Акиньшин — Поговорим про арифметику
Будут и другие доклады. Так что берите футболку, пиджак, куртку, свитер — и в Питер. Кто знает, как изменится погода за день.
Автор: JUG.ru Group