DevEx в Django — 2 часа лайвкодинга
Ребята с PiterPy выложили двухчасовой сеанс лайвкодинга, где я 2 часа (!) вживую (!) делаю проект на Django, в котором кайфово:
Ребята с PiterPy выложили двухчасовой сеанс лайвкодинга, где я 2 часа (!) вживую (!) делаю проект на Django, в котором кайфово:
Будучи разработчиком, я не любил GraphQL с самого его появления — из-за ноды, привязки к Apollo, отсутствия APM (если не покупать подписку у Apollo) и сложного, вложенного языка запросов. В принципе до сих пор ничего изменилось, но в этом посте я хочу отдельнло поговорить о своей любимой теме – тестировании.
GraphQL замечательно умеет делать одну вещь: вытаскивать данные с сервера в произвольном формате, удобном в каждый конкретный момент. «Выгрузи мне все книги — название, количество страниц, пару интересных цитат и автора, а у каждого автора покажи ФИО, фотографию и список популярных произведений» — это типичный запрос для GraphQL, с которым он справляется идеально. В REST для такой специфичной выборки пришлось бы писать отдельный эндпоинт, следить за ним и поддерживать. А тут даже кода писать не надо — один раз описал схему данных, и всё работает из коробки.
Минус в том, что вместо понятного набора эндпоинтов с заранее определённым поведением, мы получаем один эндпоинт на все наши данные. Тестировать такой эндпоинт очень больно. Первая проблема – контракт между бекендом и фронтендом: раньше мы могли написать батарею юнит-тестов, которые проверяют все возможные запросы, аутентификацию и авторизацию, а затем копипастить их для разных эндпоинтов, добавляя локальную специфику. Тесты для GraphQL так не могут — мы же не знаем, что у нас запросят в каждый конкретный момент, а значит не можем написать тесты, которые отражают реальность. Остаётся только делать тесты для типичных запросов, и надеяться, что когда фронт или бек что-то поменяет, программисты сами договорятся и друг-другу ничего не сломают.
Сложно тестировать не только контракты, но и прозводительность. Раньше мы для каждого эндпоинта могли предсказать количество тяжёлых запросов с джоинами, и даже ограничить их количество в тестах или в рантайме (по ссылкам питон, в вашем стеке будут другие инструменты). Теперь мы каждый раз не знаем, что у нас запросят, а значит можно выгрузить хоть всю базу за один запрос.
Конечно, есть бизнесы, которые выигрывают от умения отдавать по 20 сущностей на один запрос, и делают это своей core-ценностью — к примеру облачные BaaS или высокоуровневые headless CMS вроде Sanity. Но если вам надо просто отдавать на фронт десяток известных сущностей, даже если вы планируете добавить в будущем ещё пару десятков — скорее всего GraphQL обойдётся вам намного дороже чем обычный REST, потому что с самого старта вам придётся тратить намного больше сил на тесты.
Недавно задумался, что всю жизнь обхожусь без нетворкинга в его привычном понимании — не тусуюсь на конференциях (выступил и домой), не хожу на вечеринки, почти никогда не встречаюсь с кем-то без конечной цели и чёткой повестки. Все новые проекты и интересные предложения я получал либо от незнакомых мне людей, либо предлагал сам сам — людям, с которыми не был знаком лично.
Освободившееся время я предпочитаю тратить на что-то более результативное — лучше напишу пост в блог, сделаю что-то полезное в бизнесе, займусь пет-проектом или хобби. Связи, которые люди установят со мной, изучив портфолио в блоге, будут крепче и полезнее, чем связи, которые установятся просто потому, что мы оказались в одно время в одном месте.
Да, без нетворкинга не работает биздев — если вы продаёте b2b товары или услуги, и не придумали как взломать систему, то вкладывать кучу времени в знакомства с почти нулевым результатом — это ваша святая обязанность.
Ещё нетворкинг — это в том числе и рекреационная активность: общаясь с людьми, можно отдыхать. Но в большинстве случаев между пополнением списка контактов в телеге и сидением в одиночестве, я выберу одиночество.
У Школы Сильных Программистов была небольшая LMS. Делать её решили потому, что принятый в индустрии Getсourse превращает редактирование уроков в мучение (в школе привыкли писать и редактировать в Notion), а пафосные опенсорсные LMS вроде moodle годились для чего угодно, кроме обучения взрослых людей. К тому же почти во всех курсах внедрена сложна фича, которую не найти в готовых продуктах — p2p-проверка домашки, когда одни студенты смотрят и ревьюят работу других: это экономит время экспертов и здорово повышает доходимость.
Первую версию в школе написали на коленке — рендерили материалы из ноушена, но уже с профилем студента (для диплома), минимальной навигацией и кнопочкой сапорта. Написали, запустили, прожили год, а потом устали — код был не очень: фичи не попилишь, едущую вёрстку не поправишь.
Решили, раз уж все гипотезы доказаны, просто переписать всё без новых фич, но с нестыдным кодом. Сформулировали вот такую задачу:
Для старта работ у нас было:
Старый код рефакторить было бесполезно, так что решили выкинуть всё и написать всё с нуля, ориентируясь на пост с постановкой задачи. Причин для такого решения было две:
С решением не ошиблись, получилось быстро и круто.
Редизайн 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, уверен, есть ребята которые ценят анонсы — когда-то я унёс из студии прекрасную традицию писать имена сотрудников под рассказом о каждом проекте. Ну или нашу открытую разработку.
Заключая с клиентом соглашение о непереманивании, я расписываюсь, что построил компанию, люди из которой не уходят просто потому, что их не зовут. И вместо того, чтобы починить проблему, я трачу силы на возведение вокруг неё забора — получается нечестно не только по отношению к сотрудникам, но и к себе.