Фёдор Борщёв

Обхожусь без нетворкинга

Недавно задумался, что всю жизнь обхожусь без нетворкинга в его привычном понимании — не тусуюсь на конференциях (выступил и домой), не хожу на вечеринки, почти никогда не встречаюсь с кем-то без конечной цели и чёткой повестки. Все новые проекты и интересные предложения я получал либо от незнакомых мне людей, либо предлагал сам сам — людям, с которыми не был знаком лично.

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

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

Ещё нетворкинг — это в том числе и рекреационная активность: общаясь с людьми, можно отдыхать. Но в большинстве случаев между пополнением списка контактов в телеге и сидением в одиночестве, я выберу одиночество.

LMS для Школы Сильных Программистов

У Школы Сильных Программистов была небольшая LMS. Делать её решили потому, что принятый в индустрии Getсourse превращает редактирование уроков в мучение (в школе привыкли писать и редактировать в Notion), а пафосные опенсорсные LMS вроде moodle годились для чего угодно, кроме обучения взрослых людей. К тому же почти во всех курсах внедрена сложна фича, которую не найти в готовых продуктах — p2p-проверка домашки, когда одни студенты смотрят и ревьюят работу других: это экономит время экспертов и здорово повышает доходимость.

Первую версию в школе написали на коленке — рендерили материалы из ноушена, но уже с профилем студента (для диплома), минимальной навигацией и кнопочкой сапорта. Написали, запустили, прожили год, а потом устали — код был не очень: фичи не попилишь, едущую вёрстку не поправишь.

Решили, раз уж все гипотезы доказаны, просто переписать всё без новых фич, но с нестыдным кодом. Сформулировали вот такую задачу:

  • Нормальный код покрытый тестами
  • Хороший дизайн и UI-kit
  • Удобная мобильная версия для чтения на ходу

Старт

Для старта работ у нас было:

  1. Бекенд на Django, покрытый тестами
  2. Код текущего фронтенда LMS
  3. Большой пост с описанием функциональности

Старый код рефакторить было бесполезно, так что решили выкинуть всё и написать всё с нуля, ориентируясь на пост с постановкой задачи. Причин для такого решения было две:

  1. Писать хорошую дизайн-систему с нуля проще, чем рефакторить старую
  2. Cтарая LMS была написана на Vue 2, а в то время уже вышел Vue 3, в котором появилась поддержка Typescript, а ещё крутой туллинг в виде Vite и Pinia

С решением не ошиблись, получилось быстро и круто.

Редизайн LMS мы решили делать прямо в коде. Используя старую LMS как вайрфреймы, мы собрали все страницы внутри Storybook на мокнутых данных из фейкера.

Чтобы дизайн был консистентным и не отнимал много времени, мы взяли Tailwind — его атомарность позволяла быстро примерять разные варианты, а токенизированность упрощала создание компонентов в единой стилистике.

Материалы

Материалы для LMS пишутся в ноушене и отдаются на фронтенд через хитрое API. Бекенд нужен, чтобы контролировать доступ к материалам, кешировать их (чтобы грузилось быстрее, чем в самом ноушене) и немножечеко его менять, чтобы было просто рендерить на фронте.

На фронтенде материалы рендерятся в удобном интерфейсе: пригодном для чтения, с хорошо натсроенным шрифтом и с тёмной темой, Таким образом редакторы пользуются удобным и привычным текстовым редактором, а ученики читают материалы в интерфейсе школы.

Забегая вперёд: такое решение — единственная сложная часть LMS. Реализации рендеринга на Vue печальные: одна очень плохо написана, а другая редко обновляется. Сейчас мы форкнули удачную реализацию и обновляем её сами (к счастью, ноушен ничего не меняет, поэтому это не много работы).

Почему просто не использовать маркдаун? Маркдаун нужно уметь писать, а курсы в школе пишут не только программисты. Кроме того, наладить простое (git — это не простое) совместное редактировние текстов в маркдауне — тяжёлая задача.

Домашки

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

Ответы на домашку ученики пишут в удобном WYSIWYG редакторе. Редактор собран на основе tiptap. Чтобы оживить общение между студентами, мы добавили возможность оставлять реакции.

Профиль студента

По окончании каждого курса школа выдаёт кайфовый диплом: можно положить в LinkedIn, добавить в резюме или просто повесить на стенку. Чтобы в диплом было вписано корректное имя пользователя, мы сделали раздел «профиль», где студенты заполняют свои данные На странице настроек ученик управлет своими данными, а также указывает информацию, которая появится на дипломе.

К моменту работы над этой страницей уже скопилось достаточно полей, которым нужна была валидация. Делать хорошую валидацию сложно и долго, а делать среднюю — просто долго. Хотелось найти вариант, над которым не придётся думать, но при этом он будет точно понятен пользователям.

На бекенде уже была сделана хорошая валидация с понятными текстами ошибки. Чтобы забыть про валидацию на фронтенде раз и навсегда ответы с бекенда в выводятся в тосты. Перехват ошибок делается на уровне axios и все ошибки ловятся автоматически, без использования try … catch.

Релиз и что дальше

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

Релиз прошел плавно. В том, что так будет, мы были уверены — код был хорошо покрыт тестами.

Дополнительно убедиться в том, что новые фичи не развалили все прямо перед релизом, помогали тесты на визуальный регресс. Они сравнивают скриншоты актуального интерфейса с тем, как он выглядит в мастере, и показывают различия если что-то поменялось. Чтобы написать такой тест, нужно добавить историю в Storybook и написать тест который ходит туда через Playwright, делает скриншот и сравнивает его. Через такой такой тест не пройдут ошибки, затрагивающие рендер, в том числе ошибки на уровне CSS.

Код проекта открытый. Посмотреть можно на гитхабе.

Технологии: vue3, pinia, vitest, playwright.

Разработчик и автор статьи: Тимур Брачков.

Почему у нас нет соглашения о непереманивании

В кровавом аутсорсе и аутстафе принято с каждым новым клиентом, кроме договора об услугах, заключать ещё и NSA: non-solicitation agreement или соглашение о непереманивании. Типа, если сотрудник из аутсорса\аутстафа переходит на сторону клиента — клиент платит большой штраф.

Даже если отбросить юридические моменты (уверен, способы обойти эту фигню всем очевидны), такой договор мне кажется ущербным. Во-первых, это выглядит как форма крепостного права — я, как работодатель, ограничиваю волю другого человека работать там, где он хочет.

Во-вторых, сотрудники работают в компании явно не потому, что им запретили уходить. Кому-то важен гибкий график и отсутствие дейликов. Кто-то ценит проекты, коллег, или индивидуальные договорённости по оформлению и зарплате. В fands, уверен, есть ребята которые ценят анонсы — когда-то я унёс из студии прекрасную традицию писать имена сотрудников под рассказом о каждом проекте. Ну или нашу открытую разработку.

Заключая с клиентом соглашение о непереманивании, я расписываюсь, что построил компанию, люди из которой не уходят просто потому, что их не зовут. И вместо того, чтобы починить проблему, я трачу силы на возведение вокруг неё забора — получается нечестно не только по отношению к сотрудникам, но и к себе.

Зачем и как начинать проекты на Django

Этот доклад я рассказывал в 2021 году, но в 2023 всё ещё ничего не изменилось: Django — по-прежнему лучший инструмент для веб-бекенда в Python, если не пытаться тащить в неё батарейки и генерить на ней HTML.