Мы разочаровались в курсах по программированию и поэтому сделали свои собственные. Не для вайтишников, а для типичных разрабов. В процессе нас хакнул инфлюенсер и забанил сервер телеграма.
Покоцанные, но не сломленные, мы представляем проект, над которым работали полтора года по ночам. Курсы по программированию с задачами в online IDE и прагматичной теорией. Никаких сертификатов и гарантий трудоустройства. Сплошной хардкор и опенсорс!

Выучить новый язык – приключение дольше, чем на 20 минут. А раз так, возникает естественное программистское желание этот процесс оптимизировать. Чтобы за кратчайшее время получить максимум знаний для идиоматичной разработки на новом языке, свободного погружения в чужие проекты и код-ревью.
Напрашивается идея площадки с опенсорсными курсами, заточенными под разработчиков. Какое у нее принципиальное отличие от вайтишных морковок а-ля «питон за 3 месяца в рассрочку»? Площадка не вкладывает знания в клювик. Все, что она делает – не мешает учиться!
А выглядит это так. Разработчик читает актуальную теорию без воды и упрощений. И непрерывно выполняет практические задания. Их много. Но подаются они маленькими порциями.
Представьте: прямо по тексту глав курса идут online IDE с задачами. Прочитал абзац про незнакомую концепцию и тут же заполировал написанием кода! Причем для каждой задачи доступны краткая подсказка и полное решение.

Фрагмент главы «Функции высших порядков» курса по питону.
Так и родилась концепция проекта Senior Junior. Почему такое название? Да потому что каждый сеньор немного чувствует себя джуном, когда учит новый язык ;)
Для воплощения идеи в жизнь собрались четыре бэкендера. С тех пор мы – C++ программисты днем, а ночью… все те же C++ программисты, но бороздящие мутные воды фулстека.
Первым делом мы определились, в каком формате хранить главы курсов и задачи. В приоритете – удобство для сторонних контрибьютеров, ведь курсы должны быть опенсорсными. Выбор пал на язык разметки markdown.
Чтобы в вебе рендерить markdown в HTML, мы воспользовались js-библиотекой markdown-it.

Слева – сырой md-файл главы по питону. Справа – то, как выглядит отрендеренная глава на сайте. И да, мы подвезли на сайт темную тему!
Чтобы разметить по тексту глав якори для ссылок, примеры кода и задачи, нам потребовалось расширить спецификацию markdown. И в этом нам помогла библиотека markdown-it-attrs: она позволяет навешивать на результирующий HTML свои CSS-классы, id и атрибуты.
Научившись конвертировать md-файл в размеченный HTML, мы занялись расстановкой по странице главы компактных online IDE. В них пользователи могут решать задачи и запускать тесты. Для этого подошла библиотека CodeMirror. При загрузке страницы скрипт находит размеченные HTML-элементы, скармливает их CodeMirror и встраивает IDE на страницу:

Online IDE для решения задачи в главе курса по расту.
…Однако сайт у нас появился далеко не сразу. Ибо нет худшей кары для бэкендера, чем выравнивать div по высоте. Фронтендом никто из нас заниматься не хотел, поэтому вначале мы вместо него запилили телеграм-бота.
Идея простая: в боте, как и на сайте, пользователь выбирает курсы, перемещается между главами, читает их и… пишет код! Для решения задачи нужно просто отправить свой код в сообщении.

В боте удобнее проходить курсы со смартфона, а на сайте – с десктопа.
Бота мы писали, конечно же, на питоне. Шучу. На C++, так интереснее. Более того, была велика тяга сделать свой велосипед для общения с сервером телеграма. Но мы взяли себя в руки и вместо этого подключили библиотеку tgbot-cpp. Запустили бота на арендованном VPS и вчетвером принялись тестировать весь цикл прохождения курса.
Сайт у нас тоже появился, но позже. Для этого пришлось приобщиться к клепанию темплейтов на django.
И вот во что превратилась наша площадка с курсами:

Код пользователей вместе с тестами запускается в изолированных контейнерах. Этим заведует специальный C++ сервис, который взаимодействует с движком докера. Общение происходит по HTTP.
Для нас это было новостью, но docker server предоставляет REST API (Docker Engine API), а консольные команды вроде
Когда мы стартовали закрытое альфа-тестирование нашей площадки, не отходя от кассы нас по-дружески ломанул один товарищ. Тут нужно отметить, что единожды поднятый контейнер мы переиспользуем для многократного запуска в нем задач. Это быстрее, чем для каждого прогона тестов поднимать чистый контейнер.
На тот момент мы уже начали думать, как бы такой подход максимально обезопасить. Но не успели подрезать прав�� учетки, из-под которой запускается код. Как результат – в контейнере легко было удалить часть важных файлов. Что и было с удовольствием проделано. Естественно, это привело к аварии при следующем запуске задач.
Этот косяк мы спешно поправили. Впрочем, как и пачку других менее драматичных. И решили, что готовы к запуску на большую аудиторию.
Осень — идеальный сезон для выкатывания созревших сервисов на прод. Несколько итераций тестирования породили дерзкую надежду, что краник с багами надежно перекрыт. Для плавного, «поштучного» наращивания аудитории мы анонсировали проект на не самом популярном айтишном ресурсе. И с чувством выполненного долга отчалили каждый по своим делам.
Поступили мы так, конечно же, напрасно.
На площадку с курсами, проломив метафорическую вывеску «вайтишникам не входить», сотнями хлынули… Вайтишники. Вероятно, влекомые надеждой «вот уж где точно обучат».
Тут-то и начались голодные игры. Точнее, бескомпромиссные фаззи-тесты нашего бэка.
Первым пал телеграм-бот. Он ковался в жерле вулкана Modern Cpp и был готов к любым нагрузкам. Но не к изобретательности одного юного дарования. Оное вместо самостоятельного решения задачи и отправки кода в сообщении отыскало похожий пример в каком-то обучающем телеграм-канале. И форварднуло его боту.
Бот рассчитывал получить сообщение с заполненными полями
Сообщение-убийца опрокидывало бота в segfault. Systemd его стремительно перезапускал. На старте бот выгребал с сервера телеграма все необработанные сообщения, среди которых висело и это. Снова пытался его обработать. Снова падал. Веселье продолжалось до тех пор, пока телеграм не занес бота в блэк лист из-за слишком частых запросов.
В таком состоянии мы и обнаружили нашего бота: валяющимся среди собственных core dump’ов и обрывков с логами “ERROR: Too Many Requests”. Интрига! Разматывать этот клубок и гадать, с какого перепуга телеграм нас заблокировал, было увлекательно. И поучительно.
Едва мы реанимировали телеграм-бота, тут же ринулись разбираться, почему примерно у одного пользователя из ста не получается зарегистрироваться. Затем фурами отгружали на прод исправления фактологических ошибок в курсах.

В сухом остатке «мягкий запуск» нам принес 700+ регистраций, несколько десятков постоянных пользователей и 100+ ценных отзывов. Ого, на наше детище позарились не только вайтишники, но и разработчики! У нас моментально открылось второе дыхание для работы над курсами.
Сейчас у нас уже готовы курс по питону и 6 глав курса по расту.
Как только питон ни называют. Универсальный клей – за удобство написания скриптов автоматизации и всякого рода обвязок.
Лучший язык для обучения – за внешнюю простоту и низкий порог входа.
Худший язык для обучения – за то, что после низкого порога вас поджидает крутая ступенька. Масла в огонь подливает неявная динамическая типизация – виновница развешанных по коду ружей «несоответствие типов» и «неявное преобразование».

Так или иначе, но питон — это лучший второй язык в мире бэкенда: если задача не решается с помощью питона подходящим образом, то как минимум легко прототипируется.
Светлые и темные стороны языка мы постарались исследовать в 39 главах и 200+ задачах курса по питону. Нельзя сказать, что это удалось нам на 100%. Например, было трудно балансировать между прагматичным подходом к изложению и широким выбором тем, раскрывающих pythonic way во всей красе. Уважаемые питонисты, не стесняйтесь указывать нам на недочеты!
Мы посчитали нужным разобрать такие концепции как слоты, дескрипторы, метаклассы. Уже не говоря о причинах реализации в языке GIL, проекте nogil и добавлении в язык сабинтерпретаторов.
Причем для лучшего запоминания популярные фичи языка встречаются в курсе более одного раза. Взять хотя бы оператор моржа
1. Сокращение объема кода и сужение области видимости переменной.
2. Создание переменных «на лету», в том числе прямо при вызове функций.
3. Переиспользование расчетов без заведения переменной в локальном скоупе. Например, при формировании коллекций.
4. Ускорение list comprehensions.
Но главным вызовом при разработке курса по питону было придумывание задач и подкручивание их уровня сложности. Возможно, некоторые задачи получились слишком простыми либо наоборот перемудреными. Предлагайте свои варианты в нашем комьюнити!
С 2016 года раст лидирует как «самый любимый» язык в опросах от Stack Overflow. Однако бурного роста вакансий для разработчиков на расте как-то не заметно.

Кто-то считает, причиной тому высокий порог входа в язык. А кто-то загадочно улыбается и отвечает, что всему свое время и нужно просто подождать.
Так или иначе, но раст столь же производителен как C и C++ благодаря отсутствию сборщика мусора. Но при этом гарантирует безопасность работы с памятью, безопасность типов и безопасность работы с данными из нескольких потоков.
Огромное количество ошибок отлавливается в расте еще на этапе компиляции. Уже и не говорю про такие плюшки языка как алгебраические типы данных, удобный подход к обработке ошибок, менеджер пакетов Cargo… Все это позволяет писать и рефакторить проекты на расте быстрее, чем на C++ и порой даже чем на питоне!
У нас готовы пока только 6 глав курса по расту. Но уже их хватит, чтобы составить первое впечатление о возможностях языка.
Например, вы узнаете, что условия и циклы в расте – это выражения. То есть условие или цикл возвращает некое значение. Хаскелистов этим не удивить, но выходцам из ООП-мира это порой сносит крышу.
Рассмотрим пример. Возьмем очень простую последовательность чисел, называемую «сиракузской последовательностью». Чтобы ее получить, нужно:
Гипотеза Коллатца гласит, что для любого числа
Обратили внимание, как цикл-выражение влияет на стиль кода? И это только цветочки с поляны раста. Далее вас ждут ягоды и грибы с удивительными свойствами.
Итак, курс по питону у нас готов целиком. Работа над курсом по расту в самом разгаре. А недавно к проекту присоединился автор, приступивший к курсу по go. Stay tuned!
Курсы на нашей площадке мы будем развивать по нескольким направлениям.
А что насчет новых фичей? Есть у нас парочка на примете: «вопросы с собесов» и «песочница» для экспериментов с кодом.
Оставляйте свои комментарии под постом: чему бы вы хотели научиться, какие фичи считаете полезными?
Приглашаем поучаствовать в развитии курсов Senior Junior! В каком формате – выбор за вами:
Это – первый наш пост про Senior Junior на Хабре. А значит, самое время высказать свое мнение о проекте. Вэлком в комментарии ;)
Покоцанные, но не сломленные, мы представляем проект, над которым работали полтора года по ночам. Курсы по программированию с задачами в online IDE и прагматичной теорией. Никаких сертификатов и гарантий трудоустройства. Сплошной хардкор и опенсорс!

Зачем это нужно?
Выучить новый язык – приключение дольше, чем на 20 минут. А раз так, возникает естественное программистское желание этот процесс оптимизировать. Чтобы за кратчайшее время получить максимум знаний для идиоматичной разработки на новом языке, свободного погружения в чужие проекты и код-ревью.
Напрашивается идея площадки с опенсорсными курсами, заточенными под разработчиков. Какое у нее принципиальное отличие от вайтишных морковок а-ля «питон за 3 месяца в рассрочку»? Площадка не вкладывает знания в клювик. Все, что она делает – не мешает учиться!
А выглядит это так. Разработчик читает актуальную теорию без воды и упрощений. И непрерывно выполняет практические задания. Их много. Но подаются они маленькими порциями.
Представьте: прямо по тексту глав курса идут online IDE с задачами. Прочитал абзац про незнакомую концепцию и тут же заполировал написанием кода! Причем для каждой задачи доступны краткая подсказка и полное решение.

Фрагмент главы «Функции высших порядков» курса по питону.
Так и родилась концепция проекта Senior Junior. Почему такое название? Да потому что каждый сеньор немного чувствует себя джуном, когда учит новый язык ;)
От идеи до запуска
Для воплощения идеи в жизнь собрались четыре бэкендера. С тех пор мы – C++ программисты днем, а ночью… все те же C++ программисты, но бороздящие мутные воды фулстека.
Первым делом мы определились, в каком формате хранить главы курсов и задачи. В приоритете – удобство для сторонних контрибьютеров, ведь курсы должны быть опенсорсными. Выбор пал на язык разметки markdown.
Чтобы в вебе рендерить markdown в HTML, мы воспользовались js-библиотекой markdown-it.

Слева – сырой md-файл главы по питону. Справа – то, как выглядит отрендеренная глава на сайте. И да, мы подвезли на сайт темную тему!
Чтобы разметить по тексту глав якори для ссылок, примеры кода и задачи, нам потребовалось расширить спецификацию markdown. И в этом нам помогла библиотека markdown-it-attrs: она позволяет навешивать на результирующий HTML свои CSS-классы, id и атрибуты.
Научившись конвертировать md-файл в размеченный HTML, мы занялись расстановкой по странице главы компактных online IDE. В них пользователи могут решать задачи и запускать тесты. Для этого подошла библиотека CodeMirror. При загрузке страницы скрипт находит размеченные HTML-элементы, скармливает их CodeMirror и встраивает IDE на страницу:

Online IDE для решения задачи в главе курса по расту.
…Однако сайт у нас появился далеко не сразу. Ибо нет худшей кары для бэкендера, чем выравнивать div по высоте. Фронтендом никто из нас заниматься не хотел, поэтому вначале мы вместо него запилили телеграм-бота.
Идея простая: в боте, как и на сайте, пользователь выбирает курсы, перемещается между главами, читает их и… пишет код! Для решения задачи нужно просто отправить свой код в сообщении.

В боте удобнее проходить курсы со смартфона, а на сайте – с десктопа.
Бота мы писали, конечно же, на питоне. Шучу. На C++, так интереснее. Более того, была велика тяга сделать свой велосипед для общения с сервером телеграма. Но мы взяли себя в руки и вместо этого подключили библиотеку tgbot-cpp. Запустили бота на арендованном VPS и вчетвером принялись тестировать весь цикл прохождения курса.
Сайт у нас тоже появился, но позже. Для этого пришлось приобщиться к клепанию темплейтов на django.
И вот во что превратилась наша площадка с курсами:

Код пользователей вместе с тестами запускается в изолированных контейнерах. Этим заведует специальный C++ сервис, который взаимодействует с движком докера. Общение происходит по HTTP.
Для нас это было новостью, но docker server предоставляет REST API (Docker Engine API), а консольные команды вроде
docker run – всего лишь обертка над ним. За каждой из этих команд стоит один или даже несколько HTTP-запросов к движку докера.Когда мы стартовали закрытое альфа-тестирование нашей площадки, не отходя от кассы нас по-дружески ломанул один товарищ. Тут нужно отметить, что единожды поднятый контейнер мы переиспользуем для многократного запуска в нем задач. Это быстрее, чем для каждого прогона тестов поднимать чистый контейнер.
На тот момент мы уже начали думать, как бы такой подход максимально обезопасить. Но не успели подрезать прав�� учетки, из-под которой запускается код. Как результат – в контейнере легко было удалить часть важных файлов. Что и было с удовольствием проделано. Естественно, это привело к аварии при следующем запуске задач.
Этот косяк мы спешно поправили. Впрочем, как и пачку других менее драматичных. И решили, что готовы к запуску на большую аудиторию.
Запуск!
Осень — идеальный сезон для выкатывания созревших сервисов на прод. Несколько итераций тестирования породили дерзкую надежду, что краник с багами надежно перекрыт. Для плавного, «поштучного» наращивания аудитории мы анонсировали проект на не самом популярном айтишном ресурсе. И с чувством выполненного долга отчалили каждый по своим делам.
Поступили мы так, конечно же, напрасно.
На площадку с курсами, проломив метафорическую вывеску «вайтишникам не входить», сотнями хлынули… Вайтишники. Вероятно, влекомые надеждой «вот уж где точно обучат».
Тут-то и начались голодные игры. Точнее, бескомпромиссные фаззи-тесты нашего бэка.
Первым пал телеграм-бот. Он ковался в жерле вулкана Modern Cpp и был готов к любым нагрузкам. Но не к изобретательности одного юного дарования. Оное вместо самостоятельного решения задачи и отправки кода в сообщении отыскало похожий пример в каком-то обучающем телеграм-канале. И форварднуло его боту.
Бот рассчитывал получить сообщение с заполненными полями
chat и from. У пересылаемого из канала сообщения оба эти поля равны null. На проверку которого мы, конечно же, забили. Сообщение-убийца опрокидывало бота в segfault. Systemd его стремительно перезапускал. На старте бот выгребал с сервера телеграма все необработанные сообщения, среди которых висело и это. Снова пытался его обработать. Снова падал. Веселье продолжалось до тех пор, пока телеграм не занес бота в блэк лист из-за слишком частых запросов.
В таком состоянии мы и обнаружили нашего бота: валяющимся среди собственных core dump’ов и обрывков с логами “ERROR: Too Many Requests”. Интрига! Разматывать этот клубок и гадать, с какого перепуга телеграм нас заблокировал, было увлекательно. И поучительно.
Едва мы реанимировали телеграм-бота, тут же ринулись разбираться, почему примерно у одного пользователя из ста не получается зарегистрироваться. Затем фурами отгружали на прод исправления фактологических ошибок в курсах.

В сухом остатке «мягкий запуск» нам принес 700+ регистраций, несколько десятков постоянных пользователей и 100+ ценных отзывов. Ого, на наше детище позарились не только вайтишники, но и разработчики! У нас моментально открылось второе дыхание для работы над курсами.
Сейчас у нас уже готовы курс по питону и 6 глав курса по расту.
Python. Лучший для обучения. Худший для обучения
Как только питон ни называют. Универсальный клей – за удобство написания скриптов автоматизации и всякого рода обвязок.
Лучший язык для обучения – за внешнюю простоту и низкий порог входа.
Худший язык для обучения – за то, что после низкого порога вас поджидает крутая ступенька. Масла в огонь подливает неявная динамическая типизация – виновница развешанных по коду ружей «несоответствие типов» и «неявное преобразование».

Так или иначе, но питон — это лучший второй язык в мире бэкенда: если задача не решается с помощью питона подходящим образом, то как минимум легко прототипируется.
Светлые и темные стороны языка мы постарались исследовать в 39 главах и 200+ задачах курса по питону. Нельзя сказать, что это удалось нам на 100%. Например, было трудно балансировать между прагматичным подходом к изложению и широким выбором тем, раскрывающих pythonic way во всей красе. Уважаемые питонисты, не стесняйтесь указывать нам на недочеты!
Мы посчитали нужным разобрать такие концепции как слоты, дескрипторы, метаклассы. Уже не говоря о причинах реализации в языке GIL, проекте nogil и добавлении в язык сабинтерпретаторов.
Причем для лучшего запоминания популярные фичи языка встречаются в курсе более одного раза. Взять хотя бы оператор моржа
:=. Он напоминает отдыхающего на боку моржа, но любим мы его не за это. От классического оператора присваивания = он отличается тем, что не только задает значение переменной, но и возвращает его. И вот какие кейсы применения моржика мы рассмотрели в курсе:1. Сокращение объема кода и сужение области видимости переменной.
while (res := calc_next_val()) >= 0: print("Next iteration of calculation...", res)
2. Создание переменных «на лету», в том числе прямо при вызове функций.
min(a := 8, b := -2, c := 4, d := 0)
3. Переиспользование расчетов без заведения переменной в локальном скоупе. Например, при формировании коллекций.
query_stats = [q := query.strip().lower(), len(q), q.split()]
4. Ускорение list comprehensions.
normalized = [n for w in words if len(n := normalize(w)) > 1]
Но главным вызовом при разработке курса по питону было придумывание задач и подкручивание их уровня сложности. Возможно, некоторые задачи получились слишком простыми либо наоборот перемудреными. Предлагайте свои варианты в нашем комьюнити!
Rust. Самый обожаемый язык, не захвативший рынок
С 2016 года раст лидирует как «самый любимый» язык в опросах от Stack Overflow. Однако бурного роста вакансий для разработчиков на расте как-то не заметно.

Кто-то считает, причиной тому высокий порог входа в язык. А кто-то загадочно улыбается и отвечает, что всему свое время и нужно просто подождать.
Так или иначе, но раст столь же производителен как C и C++ благодаря отсутствию сборщика мусора. Но при этом гарантирует безопасность работы с памятью, безопасность типов и безопасность работы с данными из нескольких потоков.
Огромное количество ошибок отлавливается в расте еще на этапе компиляции. Уже и не говорю про такие плюшки языка как алгебраические типы данных, удобный подход к обработке ошибок, менеджер пакетов Cargo… Все это позволяет писать и рефакторить проекты на расте быстрее, чем на C++ и порой даже чем на питоне!
У нас готовы пока только 6 глав курса по расту. Но уже их хватит, чтобы составить первое впечатление о возможностях языка.
Например, вы узнаете, что условия и циклы в расте – это выражения. То есть условие или цикл возвращает некое значение. Хаскелистов этим не удивить, но выходцам из ООП-мира это порой сносит крышу.
Рассмотрим пример. Возьмем очень простую последовательность чисел, называемую «сиракузской последовательностью». Чтобы ее получить, нужно:
- Взять любое натуральное число
n. - Если
nчетное, поделить его на 2, а если нечетное — умножить на 3 и прибавить 1. - Повторить шаг 2.
Гипотеза Коллатца гласит, что для любого числа
n все закончится на единице. Эту гипотезу мы и проверим для значения 16. Напишем цикл, который возвращает количество шагов до получения 1 и максимальное значение последовательности, полученное во время вычислений.fn main() { let mut value = 16; let mut max = value; let mut step = 1; let (step, max) = loop { if value == 1 { break (step, max); } else if value % 2 == 0 { value /= 2; } else { value = 3 * value + 1; max = std::cmp::max(max, value); } step += 1; }; println!("total steps: {step}, max value: {max}\n"); }
total steps: 5, max value: 16Обратили внимание, как цикл-выражение влияет на стиль кода? И это только цветочки с поляны раста. Далее вас ждут ягоды и грибы с удивительными свойствами.
Что дальше?
Итак, курс по питону у нас готов целиком. Работа над курсом по расту в самом разгаре. А недавно к проекту присоединился автор, приступивший к курсу по go. Stay tuned!
Курсы на нашей площадке мы будем развивать по нескольким направлениям.
- Языки программирования, фреймворки, библиотеки. Kotlin, С++, C#… А как насчет щепотки функциональщины в виде Haskell?
- Глубокое погружение в конкретный аспект языка. Например, для C++ напрашиваются темы «Конкурентность и асинхронность» и «Метапрограммирование».
- Прикладные вещи. А вы когда-нибудь интересовались, как устроены современные поисковые движки? Нужно ли быть богом, чтобы написать компилятор? Что из себя представляет разработка СУБД?
- Полезные ништяки – bash, git, vim. Многие ли владеют ими в достаточной степени, чтобы и работать продуктивно, и выпендриться при случае?
А что насчет новых фичей? Есть у нас парочка на примете: «вопросы с собесов» и «песочница» для экспериментов с кодом.
Оставляйте свои комментарии под постом: чему бы вы хотели научиться, какие фичи считаете полезными?
Присоединяйтесь к опенсорс проекту
Приглашаем поучаствовать в развитии курсов Senior Junior! В каком формате – выбор за вами:
- Проходите курсы на сайте, в боте. Делитесь фидбэком. На сайте для этого в конце каждой главы есть специальная форма, а в боте — команда
/help. - Присоединяйтесь к обсуждению проекта в нашем комьюнити.
- Предлагайте свои варианты задач на замену неудачным. Мы рады новым issue и пул-реквестам на гитхабе.
- Попробуйте себя в роли автора курса или ревьюера. Делиться знаниями – это офигенно!
Это – первый наш пост про Senior Junior на Хабре. А значит, самое время высказать свое мнение о проекте. Вэлком в комментарии ;)
💗 Спасибо всем, кто тестировал наши курсы, репортил баги и оставлял фидбэк! Отдельная благодарность Тиграну Басеяну (Black product owner) за ценные советы и критику. А также Владиславу Радченко, Михаилу Шварцбурду, Евгению Боровкову, Вадиму Демидову за поддержку запуска на Product Radar! И, разумеется, Диме Беговатову tw0face за возможность рассказать о проекте на его чудесной площадке для продвижения стартапов!
