Skip to content

История моих репозиториев

Notifications You must be signed in to change notification settings

Masynchin/history

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 

Repository files navigation

История моих репозиториев

Здесь рассказывается о всех моих проектах - мотивация к созданию, их поддержка, обновление.

assistypes (2020.08.06)

Мой первый репозиторий.

Увидев метод .resize() массивов numpy, я решил повторить это для стандартного списка. В StructuredList я смог это реализовать, и он стал основой (и долгое время единственным классом) пакета assistypes.

Позже были добавлены ещё несколько классов, но после пакет перестал мною поддерживаться.

CheWeatherBot (~2020.12.20)

Телеграм-бот для погоды моего родного города - Череповца.

У меня уже был небольшой опыт написания ботов (один для ВК), так что решившись писать их для ТГ, я решил изучить что-то новое. Выбор пал на асинхронность, поэтому в качестве основы был выбран aiogram (немалую роль в выборе сыграло и это видео).

В первой версии был использован aiogram для ТГ, aiohttp для запросов к погодному сервису, sqlite для хранения данных подписчиков рассылки, и небольшая библиотека loguru для логирования.

CheWeatherBot 1.1 (2021.03.18-2021.04.27)

В качестве школьного проекта я решил выбрать CheWeatherBot, но с расширенным функционалом.

Вместо ручного парсинга JSON-ответа погодного сервера был использован pydantic. С его помощью стало легче реализовать новые функции - получение погоды в конкретное время.

Бота я решил пристроить на heroku, чтобы я и другие люди могли им пользоваться в (почти) любое время. Сначала под это была выделена новая ветвь с реализацией хранения данных в PostgreSQL (бесплатная БД на heroku) через psycopg2. Спустя некоторое время я объединил хранение данных с помощью SQLAlchemy, и стало возможным удобно тестировать на собственном ноутбуке с SQLite, а на heroku использовать PostgreSQL.

Спустя день после ввода SQLAlchemy в проект произошёл переход с синхронного на ассинхронный сервис хранения данных подписчиков рассылки. Проект стал полностью асинхронным.

Тут же были применены и менее заметные улучшения - создание отдельной папки под .py файлы, написание докстрингов.

SYB (2021.02.19-2021.04.24)

Итоговый проект в курсе Яндекс.Лицея.

Вместе с Сашей @fuetser Захаручком нам предстояло выполнить проект на flask-стаке (flask, flask-sqlalchemy, flask-restful) + Bootstrap5. Мы решили создать что-то наподобие реддита, и за два месяца смогли создать приложение с аутентификацией, категоризацией, публикацией...

Мы смогли реализовать базовые концепции соц.сетей - аккаунты, публикации, комментарии, лайки, поиск. Помимо основной работы над бекендом, Саша сильно помог с JS. Моей же сверх-задачей были модели данных, создание и взаимодействие над ними (получение постов из подписок пользователя, алгоритм сортировки постов по нашей системы оценок и т.д.).

Это был мой первый веб-проект и первое фулстак-приложение.

Tasker (2021.05.12-2021.05.18)

Сразу после сдачи проекта для Яндекс.Лицея я захотел написал своё собственное веб-приложение. В качестве идеи был выбран сам Яндекс.Лицей - площадка с курсами>задачами>уроками по программированию.

Изучая документацию aiohttp я заметил, что на нём можно писать не только клиентскую часть, но и серверную. Беря во внимание структуры предудыщего проекта, я стал искать схожие компоненты - шаблонизацию (aiohttp-jinja2), сессии (aiohttp-sessions) и асинхронную ORM (TortoiseORM).

За 60 часов в течение недели была создана рабочая версия.

CheWeatherBot 1.2 (2021.07.18-2021.07.19)

После работы над другими проектами, я вернулся с небольшими исправлениями и техническими нововведениями.

Цель

Логику менять не стал, только привёл код в единый стиль и убрал шероховатости.

Инструменты

Всю работу мне помогли сделать эти два товарища:

Black форматирует код в едином стиле. У него (практически) нет настроек. Кроме длины строки - её я ограничил в 79 символов.

Flake8 предупреждает о огрехах кода. Неиспользуемые импорты, функции с одинаковым именем, сравнение на None без is, и т.п. Но главная фишка flake8 - плагины. В проект я сразу добавил эти:

Негодование

Я очень доволен тем, как улучшился код после использования этих двух инструментов. Но я недоволен тем, как нужно настраивать их. С black всё понятно - pyproject.toml и [tool.black]. А вот flake8 так не умеет - ему надо либо setup.cfg, либо целый отдельный файл .flake8. Так у меня появляется два файла под настройки инструментов разработки, тогда как мог быть один - pyproject.toml, утверждённый стандартом.

Предлагаю вам, читатели, ознакомиться с доводами мейнтейнера flake8 в пользу неподдержки стандарта - ссылка. На момент написания этой заметки, в Python 3.11 аннонсировали встроенную поддержку TOML. А поддержку pyproject.toml в flake8 так и не аннонсировали.

Tasker 1.1 (2021.08.13-2021.09.01)

До 1 сентября оставался месяц. Всё это время занял улучшением кодобазы "Таскера".

Тесты

Я не мог начать делать рефакторинг, так как в проекте не было тестов. Из-за их отсутствия я не мог быть уверен, что приложение не сломается, если я изменю код. Поэтому моей первой целью стало написание тестов.

Стиль кода

Второй целью я сделал приведение кода в единый вид. Так с ним будет проще работать.

Выполнение

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

В этом мне помогли black и flake8. Black привёл код к единому стилю, а flake8 указал на мелкие ошибки. Я их исправил, и приступил к написанию тестов. Но перед этим ещё расставил аннотации типов. На работу кода не влияют, но помогают при разработке. Восклицают, когда в функцию передан аргумент неправильного типа, тем самым предупреждают TypeError исключения.

Написание тестов

Написать тесты сходу оказалось невозможно. Мешает плохая архитектура приложения - слой бизнес логики связан с реализаций веб-слоя. Один из примеров: в функцию create_user передаются не сами данные будущего пользователя, а объект формы (которая заполняется на странице) с этими данными. Этот объекта класса AiohttpForm, и потому функция create_user связана с реализацией AiohttpForm.

Это плохо как для самого приложения, так и для его тестирования. Из-за того, что один слой зависит от реализации другого, их труднее обновлять - меняя код на одном уровне, можно случайно сломать код на другом.

Исправление архитектуры

Главная проблема - зависимость слоя бизнес логики от реализации веб-слоя. Я это решил тем, что вынес всё связанное с aiohttp в веб-слой. Пример:

  • До:
# Веб-слой
async def web_handler(request: AiohttpRequest):
    form = request.form
    create_user(form)


# Слой бизнес-логики
async def create_user(form: AiotttpForm) -> User:
    data = await form.data()
    firstname = data["firstname"]
    lastname = data["lastname"]
    # creating logic
  • После:
# Веб-слой
async def web_handler(request: AiohttpRequest):
    data = await request.form.data()
    firstname = data["firstname"]
    lastname = data["lastname"]
    create_user(firstname, lastname)


# Слой бизнес-логики
async def create_user(firstname: str, lastname: str) -> User:
    # creating logic

Теперь слой бизнес-логики не зависит от веб-слоя. Я могу поменять слой над безнес-логикой, и он от этого не сломается.

Тесты

Вот теперь уже я мог писать тесты. Я начал, но не закончил. Добился 73% покрытия, и на этом всё. Дальше каждый тест требовал всё больше подготовлений, дублирования кода. Всё из-за другой архитектурной проблемы - реализации моделей. Между сущностями слишком много связей.

zif (2021.10.03-...)

Прошло время с работы над Tasker, я приметил некоторые проблемы проекта.

Проблемы Tasker

Я понял, что хотел бы исправить в первой версии Tasker:

  • Дублирование кода на фронте
  • Операции на одними и теми же данными, когда их можно просто хранить на клиенте (например, данные об имени пользователя)

Решение

Я подумал, что эти проблемы может решить переход на SPA. А самая популярная библиотека для SPA - React. Кстати, именно React (вместе с Django) использует Яндекс.Лицей - прототип Tasker.

Дублирование кода фронта решается переиспользуемыми компонентами. Так же, SPA позволяет хранить данные на клиенте, что решает проблему повторных запросов к одним и тем же данным.

Это моё первое знакомство с SPA, поэтому начал смотреть готовые проекты. Ими оказались geekr - React-фронт для для стороннего API, и classroom - Vue-фронт для собственного FastAPI+TortoiseORM бекенда. У первого я подсмотрел использование React, у второго - FastAPI+TortoiseORM. Так определились используемые технологии.

Практика

Сразу же переделывать Tasker я не стал, а решил опробовать новые технологии в новом проекте. В качестве прототипа я рассматривал Двач. Хоть у меня и скептичное отношение к данному ресурсу, но в качестве базы проекта он подходит отлично - отсутствие аутентификации, переиспользование компонентов (комментариев), простая структура API.

Бекенд

Я выделил следующие сущности:

  • Тема
  • Обсуждение (в теме)
  • Комментарий (в обсуждении)

Возникла проблема с реализацией комментариев. Если делать их в лоб, по типу:

comment_id │ reply_to
───────────┼─────────
1          │ Null    
───────────┼─────────
2          │ 1       
───────────┼─────────
3          │ 2       

То нельзя будет простым образом достать комментарии одного обсуждения. Есть два решения: использовать рекурсивные CTE, либо делать триггер и поле thread_id. Первый способ легче в реализации, а второй позволяет быстрее выполнять запрос. Я выбрал первый, так как триггеры не поддерживаются ни одной ORM-библиотекой. Хотя CTE тоже не особо поддерживаются. Например, в TortoiseORM их нет, поэтому в этом проекте начал использовать PeeWee.

Фронтенд

Компоненты, роутинг, состояние - всё новое, всё интересное.

Очень понравилось делать компоненты. Всё сразу модульным становится, переиспользование появляется. Работать с состоянием тоже понравилось. Больше конкретики дать не могу. Всё как-то само собой сделалось, и не заметил, как фронтенд был готов.

Отмечу pettier - black мира фронтенда. Форматирует и JS, и CSS, и HTML, и кучу смежных с ними. Использовал при разработке, очень доволен.

Интересный факт

Кодовое название проекта - zif (Zoomers Invented Forums). Интересно, что на русском оно может так и называться - зиф (Зумеры Изобрели Форумы).

Выводы

Проект показал, что Tasker можно смело переводить на SPA. Хотя перед этим надо будет решить архитектурные проблемы.

ScheduleDrawer (2021.12.12)

Вдруг, мне захотелось написать что-то на новом для себя языке программирования. Не то, чтобы Python достал, просто хотелось изучить что-то новое.

Кандидаты

Среди языков с понятным синтаксисом я выбрал следующих кандидатов:

  • Swift
  • Dart
  • Elixir
  • Ballerina

Ballerina не достаточно популярный, а Swift и Dart не поддерживаются на моём ноутбуке. Поэтому выбор пал на Elixir.

Погружение

Начал изучение с этого вводного курса. Сразу понял, что будет интересно: язык функционального стиля, нужно кардинально другое мышление. Конечно, в Python есть элементы ФП вроде функций map, filter, или библиотек functools, itertools, но это сбоку, а не посередине.

Осмысление

Я решил попробовать Elixir на небольшом проекте. Темой взял отрисовку школьного расписания, так как уже есть готовый код. Исходник небольшой, потому мне легче переделать его под новый ЯП.

Реализация

Основная сложность состояла в использовании строго неизменяемых данных. Я просто не мог использовать привычные image.x = x; image.y = y. Вместо этого нужно создавать новый объект:

%Image{width, height} = image
new_image = %Image{width: width + 10, height: height + 10}

Описать код для отрисовки можно фразой: "Всё есть изображение". Большое изображение состоит из маленьких изображений, как большой код состоит из маленького кода, большой объект из маленьких объектов, и так далее. Идея "большое состоит из малого" встретится ещё ни раз: и в Textode, и в ndnt, и, думаю, во многих будущих проектах.

Конкретно здесь эта идея реализуется так: изображения либо узлы, и у них есть дочерние изображения, либо листья, и у них нет дочерних элементов. Так, примитивные фигуры и текст - листья, строительные блоки, из которых можно построить бóльшие изображения.

Используя такой подход, я представил расписание как такой набор изображений:

┌────────────────────┐
│ Слой расписания    │
│ ┌────────────────┐ │
│ │ Слой заголовка │ │
│ │ ┌───────────┐  │ │
│ │ │ Заголовок │  │ │
│ │ └───────────┘  │ │
│ └────────────────┘ │
│ ┌─────────────┐    │
│ │ Слой уроков │    │
│ │ ┌──────┐    │    │
│ │ │ Урок │    │    │
│ │ └──────┘    │    │
│ │ ┌──────┐    │    │
│ │ │ Урок │    │    │
│ │ └──────┘    │    │
│ │ ┌──────┐    │    │
│ │ │ Урок │    │    │
│ │ └──────┘    │    │
│ └─────────────┘    │
└────────────────────┘

Работоспособность

Как я понял, Elixir - ещё молодой язык, и на нём пока ещё мало библиотек. Erlang, на котором базируется Elixir, намного взрослее, но так же мало сторонних решений. Я не смог найти библиотеку для работы с изображениями, которая могла бы на лету создавать изображения и высчитывать размер их сторон. Это являлось необходимым условием при данном подходе. То есть, я просто не мог запустить код.

Выводы

Обидно, что для моего подхода не нашлось подходящих библиотек. Но ничего страшного, главное - идея. А идея эта отлична легла (в теории) на функциональный подход. Чувствую, что из-за этого проекта стал иначе смотреть на свой код.

Textode (2021.08.12-2022.01.29)

Первый пакет для PyPI.

Для кого

Библиотека разрабатывалась для @bullbesh и его проекта PFR Instruction. Этот проект - Telegram-бот, отвечающий на частые вопросы сотрудников Северстали, выходящих на пенсию.

Алгоритм работы бота: сотрудник спрашивает заранее известный вопрос - бот отправляет заранее подготовленный ответ. То есть, все вопросы и ответы заранее подготовлены.

Проблема бота

Вся логика диалога находилась прямо в хэндлерах бота. Так, изменять диалог было трудно - переходы размазаны по хэндлерам, не видно диалог целиком. Именно это должна была решить моя библиотека.

Проблема проекта

Сначала я определил точную проблему, которыю должен решать Textode - построение диалога, не имеющего состояния. Именно таким и был бот - структура диалога задаётся наперёд, нет никаких изменяемых данных.

Решение

Сама модель диалога похожа на дерево, которое выглядит как-то так:

graph TD;
    Начало -->|"Секция 1"| Диалог1;
    Начало -->|"Секция 2"| Диалог2;
    Начало -->|"Секция 3"| Диалог3;
Loading

Почему бы сразу не представить наш диалог в виде дерева? В этом и заключается идея Textode.

Реализация

Дерево диалога представляется в виде узлов. Диалог выше описывается так:

KeyboardNode(
    "/start",
    "Начальный текст",
    buttons=[
        TextNode("Секция 1", "Текст секции"),
        TextNode("Секция 2", "Текст секции"),
        TextNode("Секция 3", "Текст секции"),
    ],
)

Название узла должно быть уникальным. Сужается область применения, но в оставшихся проектах библиотеку удобнее использовать.

Итог

Оказалось, что преумещств у Textode больше, чем только помощь в написании логики диалога:

  • Разделение диалога и его обёртки

Textode позволяет отделить логику диалога от логики представления. В случае Telegram-бота код разбивается на две части: сам диалог, и Telegram-оболочка вокруг него.

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

  • Выделение структуры диалога

Так как мы вынесли всю логику в отдельный объект, мы можем легче ориентироваться в структуре диалога.

  • Простота в измении

Вытекает из предыдущего пункта. Мы можем быстро найти, куда нужно добавить/изменить/удалить данные.

ndnt (2022.01.29)

Вдохновлённый творчеством Егора Бугаенко, я решил применить на практике новые для себя идеи. Это и послужило началом проекту.

Цель проекта

Бóльшая часть творчества Егора Бугаенко связана с ООП. Я впервые увидел такой подход к ООП, мне он очень понравился. Я решил опробовать основные принципы Егора на практике. Среди этих принципов:

  • Никаких Null (он же None)
  • Никаких геттеров и сеттеров
  • Никаких статических методов
  • Никаких глобальных переменных
  • Никакой изменяемости

И так далее. Легче перечислить, что можно :)

Проблема

Я хотел сделать небольшое приложение. Так я могу быстро написать работающий код и потратить больше времени на его осмысление и улучшение.

Темой проекта стало измерение отступов кода. Будущий инструмент должен помогать изучать проект с точки зрения среднего значения длины отступа. Как мы знаем, большая вложенность - зло.

Поведение

Инструмент должен выводить информацию об отступах как в отдельном файле, так и в целом проекте. Интерфейс инструмента - консольное приложение.

Предметная область

Я разбил предметную область на следующие сущности:

  • Файл
  • Файлы
  • Строка кода
  • Строки кода
  • Отступ строки кода
  • Средний отступ строк кода
  • Сводка по отступам

Оставалось только реализовать их в коде.

Реализация

Сначала написал тесты, потом код. Так слово за слово, и я сделал всё приложение. На всё про всё ушёл день.

Публикация пакета

После первой рабочей рабочей версии я сразу загрузил пакет на PyPI. Украсил выпуск пакета постом на reddit.

portfolio (2022.02.16-2022.02.19)

Второе вступительное задание для курса Яндекс.Лицея по Django было сверстать сайт-портфолио.

Условия задания

  • Статика
  • Никаких фреймворков
  • Семантическая вёрстка
  • Наличие тёмной темы
  • Адаптивность
  • Успешность прохождения W3CValidator

Интересное задание, единственное интересное из всего курса, но не об этом.

Дизайн сайта

Самое сложное было разработать дизайн. Но я поступил хитро - просто скопировал сам дизайн Яндекс.Лицея:

  • Главная страница сайта Яндекс.Лицея:

Главная страница сайта Яндекс.Лицея

  • Главная страница моего портфолио:

Главная страница моего портфолио

В Safari какие-то проблемы со шрифтом логотипа, в оригинале это шрифт старого логотипа Яндекса

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

Семантическая вёрстка

Очень понравилось работать с чистым HTML и CSS, особенно вместе с условием "семантической вёрстки". Вначале поставил себе правило не использовать тег div, и так и не нарушил его. Из-за этого получившийся код легко читать. Пример DOM-дерева страницы со статьёй:

<!DOCTYPE html>
<html lang="ru">
  <head>...</head>
  <body>
    <header>...</header>
    <main>
      <a class="crumbs" href="index.html">...</a>
      <article>
        <h1>Адаптивность</h1>
        <p>...</p>
        <p>...</p>
        <p>...</p>
      </article>
    </main>
    <aside id="menu" class="menu" hidden>...</aside>
    <footer>...</footer>
  </body>
</html>

Такой трюк стал возможен и из-за специфичного CSS. Стилизация элементов, в основном, идёт по HTML-тегам, а не классам. Это видно на примере: только у хлебных крошек и меню есть свой класс, у остальных элементов его нет.

Github-Pages

Когда тестировал адаптивность под телефоны, было неудобно пользоваться инструментами разработчика. Поэтому я решил прикрутить к портфолио github-pages. Условия позоволяли - полностью статический сайт, готовый репозиторий. Так я сделал свой первый сайт на github-pages.

Валидация

Ещё одна автоматизация - проверка на W3CValidator. Для этого я использовал этот action. А ещё добавил результат проверки в виде шильдика в README.

Итоги

Организаторы зачли почти максимум за задание, отбор был пройден, курс был начат и досрочно покинут. А сайт так и работает.

Textode 2 (2022.03.12)

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

Следующее обновление должно было решить эту проблему. Казалось, что оно будет небольшим, но в итоге вылилось в обновление до версии 2.x. Сейчас объясню, почему так получилось.

Причины

Все доводы также собраны в пулл-реквесте с обновлением.

Проблема заключалась в реализации MultiNode. Она сама и её дочерние узлы должны иметь одинаковый заголовок. Почему? Всё из-за реализации Node. Каждая Node сама определяет своё название. В случае с MultiNode, нам нужен только один заголовок - для MultiNode, дочерним же узлам мы не хотим давать отдельные названия. Из-за этого приходилось передавать одинаковое название как в MultiNode, так и в её дочерние узлы. То, что это правильно работало, всего лишь особенность NodeDict.

Решение

Решение оказалось интересным. Вместо того, чтобы узел сам определял своё название, родительский узел сам должен определять связи (они же названия) со своими дочерними узлами. Это хорошо видно на примере KeyboardNode.

  • До:
KeyboardNode(
    Text("Something interesting", ...),
    Text("Current time?", ...),
    Text("Help!", ...),
)
  • После:
KeyboardNode(
    "Something interesting": Text(...),
    "Current time?": Text(...),
    "Help!": Text(...),
)

Теперь Node не должна сама определять своё название.

Реализация

Из всех подклассов Node убран аттрибут названия узла. В родительские узлы теперь передаётся словарь из пар "название - узел". Поменялась и регистрация узлов. NodeDict стал не нужен, и регистрация стала происходить через отдельную процедуру.

Из-за этих изменений была потеряна обратная совместимость. Зато внешний и внутренний код стал чище - его количество уменьшилось. Побочные действия в виде NodeDict исчезли. Тестирование стало легче.

ndnt 1.1 (2022.04.20-2022.04.22)

Функционал почти не изменился, но было улучшено оформление проекта. README стал подробнее, добавлены CHANGELOG и github-actions для тестов. А ещё добавил гайд для контрибьюторов. Всё это я делал впервые.

Подробный README

В README сделал отдельную секцию "Usage", в которой под каждую опцию ndnt'а выделен отдельный пункт. Позаимстовал эту манеру у README для fd - одного из лучших CLI-инструментов.

Первый CHANGELOG

Семантическое версионирование поддерживалось с самого начала, изменения между версиями описывались в релизах. Было трудновато каждый раз вспоминать/пробегать коммиты, чтобы написать очередное описание к новой версии. С целью удобного ведения изменений проекта был создан CHANGELOG-файл. В качестве стандарта был выбран Keep a Changelog. На сайте подробно указано, какие именно изменения должны попадать в CHANGELOG, как эти изменения группировать, как обновлять файл во время новых релизов - очень доходчиво для новичков, как я.

Первые github-actions для тестов

В проекте уже было тестирование, но проводилось оно мною вручную. Оставалось только перенести это в github-actions. Когда речь зашла о github-actions, я сразу всполнил о @tiangolo. Каждый его проект служит образцом правильного ведения репозитория. В том числе, и образцом правильных github-actions. Я сразу пошёл смотреть, как сделано автоматическое тестирование в fastapi. При попытке создать github-action возникли проблемы с codecov. Казалось, что подключение займёт больше, чем эти две строки:

- name: Upload coverage
  uses: codecov/codecov-action@v3

Но нет, всё оказалось настолько просто. С частью обычного тестирования проблем не возникло.

Новый github-action заработал с первого раза, что немного удивило меня. После успешного запуска автоматического тестирования я добавил новые значки в README - для статуса прохождения тестов и для покрытия кода.

Первый гайд для контрибьюторов

И последнее изменение. Как я упоминал в предыдущей статье, первый релиз я сопроводил постом на реддит. Но я только показал свой проект, не предоставив никакой возможности помочь проекту, поучаствовать в разработке. Именно это я исправил, создав гайд для контрибьюторов. Но сначала я сам поставил себя в роль контрибьютора. Для этого я запретил делать git push в главную ветку, теперь изменения можно делать только через пулл-реквесты. Каждый пулл-реквест должен закрывать Issue, проходить проверки github-actions, и иметь одобрение главного по репозиторию (то есть моё).

Проходя через это всё, я понял, что поможет контрибьютору моего проекта:

В CONTRIBUTING-файле я указал, как именно можно помочь проекту. Это либо создание Issue, либо создание Pull Requests. Так же для каждого из этих видов помощи я указал инструкцию по правильному оформлению. Для Issue это тема жалобы (доклад о неисправности, предложение нового функционала) и правильное название жалобы. Для Pull Requests требований больше. Это и наличие соответсвующей жалобы, и стиль коммитов, и стиль кода, и работоспособность кода. Такие строгие правила предоставляют контрибьюторам чёткую инструкцию к тому, как помочь проекту. Мне же такие жёсткие правила помогают сохранять качество кода и целостность проекта.

Также я создал шаблоны для Issue и Pull Requests. На каждый тип жалобы я сделал отдельный шаблон. Так, в шаблоне для жалобы о неисправности указаны поля "Описание проблемы", "Как возпроизвести проблему", "Ожидаемый результат", "Действительный результат". А в шаблоне жалобы с предложением нового функционала указано поле "Ожидамая функциональность". Разные шаблоны под разные типы жалоб помогают контрибьюторам правильно структурировать запросы.

Итого

Теперь пользователям легче узнать о возможностях инструмента и его обновлениях. Контрибьюторам стало проще участвовать в проекте. Качество проекта стабилизировалось, так как стало больше автоматических проверок.

Logos (2022.05.03-...)

Репозиторий с логотипами для моих проектов. А ещё самодельный редактор для них.

Логотипы

Я решил делать логотипы для моих репозиториев из-за этой статьи. Сильно красивые логотипы я делать не умею, поэтому решил делать простые векторные. Для этого отлично подходит SVG. Кроме того, логотипы в SVG будут весить меньше PNG и JPEG аналогов.

Редактор

Так как SVG основан на XML, его легко править руками. Поэтому свой первый логотип я и сделал вручную - логотип для Textode содержит всего три фигуры: два кружка и ломаную. Я решил посмотреть, как лучше стилизовать их, для чего добавил немного HTML и CSS. Убедился, какой цвет и толщину линий использовать, и утвердил первый логотип.

После этого я решил не делать логотипы для других проектов, а сделать редактор. База есть, осталось добавить возможность добавлять и двигать фигуры. Для этого я решил написать JS-скрипт. Но так было бы слишком просто, поэтому я решил использовать TypeScript, а для фигурок RxJS.

В редакторе может быть несколько фигур, и на каждое изменение любой из них нужно обновлять логотип. Поэтому RxJS отлично подходит. Пример:

Интерфейс редактора. Слева панель с настройками стиля и фигур, справа - логотип

Здесь логотип - поток из стиля и фигур. За поток стиля отвечает виджет "Appearance". Этот поток стиля - объединение потоков ширины логотипа, цвета линии, и ширины линии. С фигурами похожая ситуация. Это объединение потоков каждой из фигур. Каждый виджет - поток своей фигуры. Также это и объединение потоков параметров фигуры.

Состояние редактора

Я ещё не дописал редактор. Ещё нельзя скачивать логотип, загружать из уже существующего. Нельзя добавлять свои фигуры. Но сама идея показала жизнь, поэтому скоро будет сделано и остальное.

About

История моих репозиториев

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published