В сентябре мы выпустили плагин для IntelliJ IDEA с поддержкой Python и Java. О процессе разработки, и о том, почему плагин упростит жизнь учащихся программированию на Stepik.org, расскажем в этой статье.
![](https://habrastorage.org/r/w1560/files/3af/331/407/3af33140760846d28216706f547a1dd1.png)
Плагин, как и в случае со Stepik Telegram bot, и мобильными приложениями под iOS и Android, проектировал наш новый стажёр Пётр Богданов, студент Computer Science Center в Санкт-Петербурге.
Зачем мы его делали? Разумеется, чтобы упростить жизнь студентам, не заставлять выполнять их рутинные операции, позволить полностью сконцентрироваться на процессе обучения.
Первая трудность, с которой сталкивается студент при прохождении курса по программированию на платформе, это необходимость копипаста в браузер из IDE. Программировать в браузере нелегко: нельзя запустить код и проверить его локально, нет автодополнения и рефакторинга и многого другого. Также, программируя в IDE, необходимо постоянно подглядывать в браузер, чтобы посмотреть условия задачи или скопировать Sample Input.
Вторая трудность — это проблема организации кода в проекте. Студенты, набирая код в песочнице, как правило решают только текущую задачу и не задумываются над тем, где они будут решать следующую задачу. И скорее всего, студент либо не сохраняет предыдущие решения, либо файлы у него называются наподобие “new_file” “new_file7” “new_file777”. Всё это усложняет навигацию и затрудняет переиспользование кода.
В июне этого года мы выпустили плагин, который поддерживал только Java, авторизовывался в менеджере проектов и взаимодействовал со Stepik.org с помощью контекстных меню. Но он обладал и существенными недостатками в архитектуре.
Как удобной для изучения программирования платформе нам важно поддерживать как можно больше языков программирования. А плагин условно можно разделить на две части: независимую от поддерживаемого языка (авторизация, взаимодействие с API, настройки) и непосредственно поддержку языка (в основном, построение проекта).
Так как старый плагин был монолитным, рациональным образом добавить поддержку новых языков и писать новые плагины для других IDE не было возможности. Поэтому, было решено перейти на ядро обучающих плагинов от команды PyCharm.
Чтобы пользовательские данные не терялись при перезапуске, их необходимо сохранять. Для этого в IDEA есть интерфейс PersistentStateComponent, с помощью которого можно сериализовать в .xml интересующий вас класс. В документации это не указано, но подразумевается, что класс, реализующий PersistentStateComponent, — это синглтон, который нужно инстанцировать одним из трёх способов, по уровню компоненты: Application level, Project level и Module level.
В первом случае синглтон будет единственный на весь плагин, и разумно в нём хранить глобальные настройки.
В остальных случаях синглтонов может быть много и сериализоваться они будут в ./.idea. Именно на уровне проекта мы храним пользовательские данные (имя, токен и прочее), и почти всю мета информацию о курсе.
Резонный вопрос — где тогда хранить данные, если ни один проект не открыт? На такой случай в IDEA существует defaultProject, получить который можно так:
Оттуда мы берём credentials, когда создаём проект, и именно поэтому просим пользователя закрыть все проекты перед тем, как залогиниться в настройках явно.
Реализовать этот интерфейс можно двумя способами (подробнее см. документацию), кроме этого нужно обязательно объявить эту компоненту в plugin.xml (самый главный .xml) в соответствии с уровнем, например:
Вообще, реализовав любой интерфейс из IntelliJ API, его необходимо объявить в plugin.xml.
А для хранения паролей можно использовать встроенный менеджер паролей PasswordSafe. Именно из-за обращения к нему время от времени возникают такие окна:
![](https://habrastorage.org/r/w1560/files/13b/9e6/198/13b9e61984ee4cf1b01c21f865a3655a.png)
![](https://habrastorage.org/r/w1560/files/1db/4ad/1e5/1db4ad1e54fd4343bde7e1dd0f8903ce.png)
Stepik.org поддерживает полноценную OAuth 2 авторизацию. Но в плагине пока что реализована только авторизация через логин и пароль. С другими типами авторизации есть проблема, в том что придётся поднимать сервер на localhost для прослушки redirected_url.
Для общения со Стэпиком в ядре уже существовал класс EduStepicConnector, который содержал большой набор статических методов, и экземпляр HttpClient для выполнения запросов. Этот класс было решено разбить на 4 класса:
![](https://habrastorage.org/r/w1560/files/3d4/54c/08a/3d454c08ac014bbc9c254029d49e49d1.png)
В Client Init инициализируется HttpClient и решается проблема с проверкой сертификата. У Стэпика сертификат от Let's Encrypt, а IdenTrus CA был добавлен только в Java 8u101. StepikConnectorLogin отвечает за авторизацию. А остальные классы уже могут совершать запросы, требующие авторизации и нет.
В такой схеме может быть только один активный клиент, но её не сложно расширить на несколько, создавая экземпляры авторизованных клиентов. Однако, мы не хотим потворствовать студентам, ведущим на Cтэпике двойную жизнь :)
Построение дерева проекта сильно изменилось относительно первой версии плагина, но слабо относительно ядра.
Теперь курс скачивается, кешируется и только затем строится из кеша. Реализовано это было из-за медленного построения проекта: чтобы скачать весь курс, нужно совершить порядка 100 запросов. Здесь существенного ускорения удалось достичь, объединяя много id в один запрос к API.
Июньская версия плагина поддерживала Яндекс.Переводчик, чтобы перевести названия курса, уроков и секций на английский. Это было нужно для того, чтобы имена пакетов для Java были на английском, а шагу соответствовал конкретный файл. И было немного неудобно. Приходилось редактировать файл перед отправкой и накладывало дополнительные ограничения.
Сейчас же в этом нет такой необходимости, потому что уровень шага теперь соответствует директории, в которой находится source. Но, тем не менее, директории сейчас носят рабочие названия (lesson1/task1), и с помощью TreeStructreProvider происходит фиктивная подмена имён директорий и они отображаются на языке курса.
![](https://habrastorage.org/r/w1560/files/998/204/6f1/9982046f1e9d483e89550cd02d620c7d.png)
TreeStructureProvider включён / выключен.
С помощью TreeStructureProvider скрывается и директория ./src/hide, в которой хранятся шаблоны шага на разных языках. А при смене языка файлы перемещаются.
![](https://habrastorage.org/r/w1560/files/05d/238/35d/05d23835ddfc453a8a14ba5fd704c9f2.png)
На картинке изображены все известные нам образовательные плагины от JetBrains, а также Стэпик плагин и его зависимости. Сиреневым показаны плагины для PyCharm. Видно, что нашему плагину для работы необходимо ещё 3 плагина. Зависимость от Python ещё правильно не настроена (поэтому его приходится устанавливать вручную). Интересно, что для Community и Ultimate IDEA полагаются разные плагины. Edu-IntelliJ — это просто точка расширения для менеджера проектов. Возможно, эту зависимость мы уберём.
И остаётся самая главная зависимость от ядра: текущие изменения в ядре ещё не залиты на официальный репозиторий, поэтому придётся устанавливать вручную нестабильную версию. И в таком случае плагины Edu-Java и Edu-Kotlin у вас пока что работать не будут.
Первое, что мы добавили — это авторизацию в настройках, а-ля GitHub.
![](https://habrastorage.org/r/w1560/files/977/aff/f17/977afff17cde4edd941ff42266446a83.png)
Но, если вы всё-таки пропустите это действие, то встретите более навязчивую авторизацию.
![](https://habrastorage.org/r/w1560/files/49c/b72/751/49cb72751a624f52a903668fbd49a2ee.png)
При построении проекта можно выбрать курс из списка курсов, на которые вы подписаны. Но это не значит, что все они совместимы с плагином. Чтобы курс создался без ошибок, в нём должен быть хоть один шаг с задачей на программирование.
![](https://habrastorage.org/r/w1560/files/eab/21c/ba6/eab21cba680a4a838f2ef1645ffb6058.png)
В этом окне вы можете выбрать желаемый язык программирования, но если он не будет доступен, то будет выбран наиболее популярный.
Ещё есть возможность выгрузить курс по ссылке, при этом, если вы не были ранее подписаны на курс, происходит подписка. В поле для ссылки можно вводить как id курса, так и любую ссылку из курса.
Статус шага отображается в дереве проекта:
![](https://habrastorage.org/r/w1560/files/5f2/069/c96/5f2069c96f3a4460a8554dc5cfa1c32a.png)
А основные действия находятся на панели Task Description справа.
![](https://habrastorage.org/r/w1560/files/bae/ae9/8c1/baeae98c1f344c7685e8e18eb79a29cf.png)
Среди них: отправка решения, предыдущий/следующий шаг, начать сначала (пока недоступно), загрузка последнего решения и смена языка.
У Stepik.org пока что нет API для того, чтобы понимать, совместим ли конкретный курс со сторонним приложением, поэтому полезно представлять как всё работает.
После авторизации плагин скачивает дерево проекта, для этого он собирает информацию о всех шагах в открытой части курса. Затем он сохраняет данные только для поддерживаемых шагов. На данный момент это только задачи типа “code”. Однако, данный тип задач обладает особенностью — в нем используются скрытые шаблоны. Скрытые шаблоны — это куски кода, которые добавляются в начало и конец файла. И по определению они недоступны для студента.
Рассмотрим на примере Java. С помощью шаблонов преподаватель может создавать задания на реализацию отдельного метода, а обёртка метода в класс происходит уже на сервере. Таким образом, у студента не будет компилироваться правильное решение, потому что весь код Java обязан быть в классе.
Но хорошие новости в том, что таких задач не так уж и много. Они чаще всего встречаются в языковых курсах.
Поэтому плагин идеально подходит для курса по алгоритмам и Hadoop.
В ближайшей перспективе мы хотим развивать поддержку разных языков программирования. На данный момент достаточно легко в Stepik Union можно добавить R, Scala, но, например, поддержка Haskell ещё слишком сырая. А с С++ сложнее, тут придется писать отдельный плагин для CLion.
Кроме того, мы рассматриваем осуществление поддержки плагином других типов задач.
Выражаем благодарность команде PyCharm за оказанную помощь и качественное ядро.
Будем рады ответить на вопросы, получить обратную связь, предложения и конструктивную критику по плагину в комментариях и в обсуждении с автором плагина ВК.
Ссылки: Stepik.org plugins, StepikOrg/intellij-community, Stepik API doc, IntelliJ Platform SDK Documentation, Repository for IntelliJ Platform SDK Documentation.
![](https://habrastorage.org/files/3af/331/407/3af33140760846d28216706f547a1dd1.png)
Плагин, как и в случае со Stepik Telegram bot, и мобильными приложениями под iOS и Android, проектировал наш новый стажёр Пётр Богданов, студент Computer Science Center в Санкт-Петербурге.
Назначение плагина
Зачем мы его делали? Разумеется, чтобы упростить жизнь студентам, не заставлять выполнять их рутинные операции, позволить полностью сконцентрироваться на процессе обучения.
Первая трудность, с которой сталкивается студент при прохождении курса по программированию на платформе, это необходимость копипаста в браузер из IDE. Программировать в браузере нелегко: нельзя запустить код и проверить его локально, нет автодополнения и рефакторинга и многого другого. Также, программируя в IDE, необходимо постоянно подглядывать в браузер, чтобы посмотреть условия задачи или скопировать Sample Input.
Вторая трудность — это проблема организации кода в проекте. Студенты, набирая код в песочнице, как правило решают только текущую задачу и не задумываются над тем, где они будут решать следующую задачу. И скорее всего, студент либо не сохраняет предыдущие решения, либо файлы у него называются наподобие “new_file” “new_file7” “new_file777”. Всё это усложняет навигацию и затрудняет переиспользование кода.
Процесс разработки
В июне этого года мы выпустили плагин, который поддерживал только Java, авторизовывался в менеджере проектов и взаимодействовал со Stepik.org с помощью контекстных меню. Но он обладал и существенными недостатками в архитектуре.
Как удобной для изучения программирования платформе нам важно поддерживать как можно больше языков программирования. А плагин условно можно разделить на две части: независимую от поддерживаемого языка (авторизация, взаимодействие с API, настройки) и непосредственно поддержку языка (в основном, построение проекта).
Так как старый плагин был монолитным, рациональным образом добавить поддержку новых языков и писать новые плагины для других IDE не было возможности. Поэтому, было решено перейти на ядро обучающих плагинов от команды PyCharm.
Рассмотрим подробно:
- Сохранение пользовательских данных
- Авторизация и общение по сети
- Построение дерева проекта
Сохранение пользовательских данных
Чтобы пользовательские данные не терялись при перезапуске, их необходимо сохранять. Для этого в IDEA есть интерфейс PersistentStateComponent, с помощью которого можно сериализовать в .xml интересующий вас класс. В документации это не указано, но подразумевается, что класс, реализующий PersistentStateComponent, — это синглтон, который нужно инстанцировать одним из трёх способов, по уровню компоненты: Application level, Project level и Module level.
В первом случае синглтон будет единственный на весь плагин, и разумно в нём хранить глобальные настройки.
В остальных случаях синглтонов может быть много и сериализоваться они будут в ./.idea. Именно на уровне проекта мы храним пользовательские данные (имя, токен и прочее), и почти всю мета информацию о курсе.
Резонный вопрос — где тогда хранить данные, если ни один проект не открыт? На такой случай в IDEA существует defaultProject, получить который можно так:
ProjectManager.getInstance().getDefaultProject()
Оттуда мы берём credentials, когда создаём проект, и именно поэтому просим пользователя закрыть все проекты перед тем, как залогиниться в настройках явно.
Реализовать этот интерфейс можно двумя способами (подробнее см. документацию), кроме этого нужно обязательно объявить эту компоненту в plugin.xml (самый главный .xml) в соответствии с уровнем, например:
<projectService serviceInterface="com.jetbrains.edu.learning.StudyTaskManager"
serviceImplementation="com.jetbrains.edu.learning.StudyTaskManager"/>
Вообще, реализовав любой интерфейс из IntelliJ API, его необходимо объявить в plugin.xml.
А для хранения паролей можно использовать встроенный менеджер паролей PasswordSafe. Именно из-за обращения к нему время от времени возникают такие окна:
![](https://habrastorage.org/files/13b/9e6/198/13b9e61984ee4cf1b01c21f865a3655a.png)
![](https://habrastorage.org/files/1db/4ad/1e5/1db4ad1e54fd4343bde7e1dd0f8903ce.png)
Авторизация и общение по сети
Stepik.org поддерживает полноценную OAuth 2 авторизацию. Но в плагине пока что реализована только авторизация через логин и пароль. С другими типами авторизации есть проблема, в том что придётся поднимать сервер на localhost для прослушки redirected_url.
Для общения со Стэпиком в ядре уже существовал класс EduStepicConnector, который содержал большой набор статических методов, и экземпляр HttpClient для выполнения запросов. Этот класс было решено разбить на 4 класса:
![](https://habrastorage.org/files/3d4/54c/08a/3d454c08ac014bbc9c254029d49e49d1.png)
В Client Init инициализируется HttpClient и решается проблема с проверкой сертификата. У Стэпика сертификат от Let's Encrypt, а IdenTrus CA был добавлен только в Java 8u101. StepikConnectorLogin отвечает за авторизацию. А остальные классы уже могут совершать запросы, требующие авторизации и нет.
В такой схеме может быть только один активный клиент, но её не сложно расширить на несколько, создавая экземпляры авторизованных клиентов. Однако, мы не хотим потворствовать студентам, ведущим на Cтэпике двойную жизнь :)
Построение дерева проекта
Построение дерева проекта сильно изменилось относительно первой версии плагина, но слабо относительно ядра.
Теперь курс скачивается, кешируется и только затем строится из кеша. Реализовано это было из-за медленного построения проекта: чтобы скачать весь курс, нужно совершить порядка 100 запросов. Здесь существенного ускорения удалось достичь, объединяя много id в один запрос к API.
Июньская версия плагина поддерживала Яндекс.Переводчик, чтобы перевести названия курса, уроков и секций на английский. Это было нужно для того, чтобы имена пакетов для Java были на английском, а шагу соответствовал конкретный файл. И было немного неудобно. Приходилось редактировать файл перед отправкой и накладывало дополнительные ограничения.
Сейчас же в этом нет такой необходимости, потому что уровень шага теперь соответствует директории, в которой находится source. Но, тем не менее, директории сейчас носят рабочие названия (lesson1/task1), и с помощью TreeStructreProvider происходит фиктивная подмена имён директорий и они отображаются на языке курса.
![](https://habrastorage.org/files/39d/832/f95/39d832f95e1e414fa7d8c92759bf047d.png)
![](https://habrastorage.org/files/998/204/6f1/9982046f1e9d483e89550cd02d620c7d.png)
TreeStructureProvider включён / выключен.
С помощью TreeStructureProvider скрывается и директория ./src/hide, в которой хранятся шаблоны шага на разных языках. А при смене языка файлы перемещаются.
Зависимость плагинов
![](https://habrastorage.org/files/05d/238/35d/05d23835ddfc453a8a14ba5fd704c9f2.png)
На картинке изображены все известные нам образовательные плагины от JetBrains, а также Стэпик плагин и его зависимости. Сиреневым показаны плагины для PyCharm. Видно, что нашему плагину для работы необходимо ещё 3 плагина. Зависимость от Python ещё правильно не настроена (поэтому его приходится устанавливать вручную). Интересно, что для Community и Ultimate IDEA полагаются разные плагины. Edu-IntelliJ — это просто точка расширения для менеджера проектов. Возможно, эту зависимость мы уберём.
И остаётся самая главная зависимость от ядра: текущие изменения в ядре ещё не залиты на официальный репозиторий, поэтому придётся устанавливать вручную нестабильную версию. И в таком случае плагины Edu-Java и Edu-Kotlin у вас пока что работать не будут.
Новый UI
Первое, что мы добавили — это авторизацию в настройках, а-ля GitHub.
![](https://habrastorage.org/files/977/aff/f17/977afff17cde4edd941ff42266446a83.png)
Но, если вы всё-таки пропустите это действие, то встретите более навязчивую авторизацию.
![](https://habrastorage.org/files/49c/b72/751/49cb72751a624f52a903668fbd49a2ee.png)
При построении проекта можно выбрать курс из списка курсов, на которые вы подписаны. Но это не значит, что все они совместимы с плагином. Чтобы курс создался без ошибок, в нём должен быть хоть один шаг с задачей на программирование.
![](https://habrastorage.org/files/eab/21c/ba6/eab21cba680a4a838f2ef1645ffb6058.png)
В этом окне вы можете выбрать желаемый язык программирования, но если он не будет доступен, то будет выбран наиболее популярный.
Ещё есть возможность выгрузить курс по ссылке, при этом, если вы не были ранее подписаны на курс, происходит подписка. В поле для ссылки можно вводить как id курса, так и любую ссылку из курса.
Статус шага отображается в дереве проекта:
![](https://habrastorage.org/files/5f2/069/c96/5f2069c96f3a4460a8554dc5cfa1c32a.png)
А основные действия находятся на панели Task Description справа.
![](https://habrastorage.org/files/bae/ae9/8c1/baeae98c1f344c7685e8e18eb79a29cf.png)
Среди них: отправка решения, предыдущий/следующий шаг, начать сначала (пока недоступно), загрузка последнего решения и смена языка.
Совместимость
У Stepik.org пока что нет API для того, чтобы понимать, совместим ли конкретный курс со сторонним приложением, поэтому полезно представлять как всё работает.
После авторизации плагин скачивает дерево проекта, для этого он собирает информацию о всех шагах в открытой части курса. Затем он сохраняет данные только для поддерживаемых шагов. На данный момент это только задачи типа “code”. Однако, данный тип задач обладает особенностью — в нем используются скрытые шаблоны. Скрытые шаблоны — это куски кода, которые добавляются в начало и конец файла. И по определению они недоступны для студента.
Рассмотрим на примере Java. С помощью шаблонов преподаватель может создавать задания на реализацию отдельного метода, а обёртка метода в класс происходит уже на сервере. Таким образом, у студента не будет компилироваться правильное решение, потому что весь код Java обязан быть в классе.
Но хорошие новости в том, что таких задач не так уж и много. Они чаще всего встречаются в языковых курсах.
Поэтому плагин идеально подходит для курса по алгоритмам и Hadoop.
Планы на будущее
В ближайшей перспективе мы хотим развивать поддержку разных языков программирования. На данный момент достаточно легко в Stepik Union можно добавить R, Scala, но, например, поддержка Haskell ещё слишком сырая. А с С++ сложнее, тут придется писать отдельный плагин для CLion.
Кроме того, мы рассматриваем осуществление поддержки плагином других типов задач.
Благодарности
Выражаем благодарность команде PyCharm за оказанную помощь и качественное ядро.
Заключение
Будем рады ответить на вопросы, получить обратную связь, предложения и конструктивную критику по плагину в комментариях и в обсуждении с автором плагина ВК.
Ссылки: Stepik.org plugins, StepikOrg/intellij-community, Stepik API doc, IntelliJ Platform SDK Documentation, Repository for IntelliJ Platform SDK Documentation.