Нам нужны твои мозги

Хотите расти как разработчик и найти крутую работу? Не протирайте штаны — займитесь Open Source проектами. Так легче всего попасть в лучшие команды разработчиков и положить себе в резюме настоящий проект, вместо нелепых «примеров кода». Но найти подходящий проект для участия сложно. Начинаются лень и отговорки, а за ними — отсутствие профессионального роста, критики по-настоящему крутых программистов, уныние и застой.

На Cult of Martians мы собираем интересные задачи для современных веб-программистов. Можно выбрать подходящую по сложности, продолжительности и специализации. Задачи не выдуманы «из воздуха» — каждая решает насущную проблему, и решить ее можно через создание нового Open Source проекта или улучшение существующего. Решайте задачи, прокачивайтесь, присылайте решение на оценку. Лучших могут пригласить к себе на работу компании, программистам которых понравится ваше решение.

Помощь запрашивал Вова Дем Вова ДемВова Дем

Помог Александр Аброськин Александр АброськинАлександр Аброськин

Бэк: GraphQL Ruby: «умная» выборка полей из БД

Для уверенных в себе, задача на несколько дней

Gem graphql-ruby предоставляет объектно-ориентированный интерфейс для построения GraphQL API на Ruby.

Одной из ключевых особенностей GraphQL является возможность запросить клиентом только те данные, которые ему нужны (а не все те, которые предлагает API).

Однако, запросы к БД, которые выполняются при работе, например, с Active Record, не являются оптимальными: используется "SELECT * ..." вместо выборки лишь тех полей, которые необходимы для формирования ответа клиенту.

При большом количестве колонок в таблице или при хранении значений большого размера выгрузка всех полей и инициализация Active Record могут привести к разбуханию памяти или отрицательно повлиять на скорость выполнения запроса.

Необходимо написать плагин (gem) для graphql-ruby, который позволит «помочь» делать более эффективные запросы.

Польза: познакомиться с GraphQL в Ruby, получить опыт в Ruby open source, принести пользу сообществу.

Пример работы и возможный API

Рассмотрим следующий запрос:

query {
  posts {
    id
    title
  }
}

На стороне Ruby мы опишем наш интерфейс следующим образом:

module GraphqlAPI
  module Types
    class Query < GraphQL::Schema::Object
      field :posts, Types::Post, null: false

      def posts
        Post.all
      end
    end
  end
end

При выполнении GraphQL-запроса будет выполнен следующий запрос в БД: SELECT * FROM posts, хотя нам было бы достаточно запросить всего два поля: id и title.

Учитывая, что GraphQL-запрос содержит информацию о запрашиваемых полях, мы можем использовать ее для построения более эффективного запроса в БД, например, используя следующий API:

module GraphqlAPI
  module Types
    class Query < GraphQL::Schema::Object
      # добавить наш плагин в базовый класс для полей (см. ниже)
      field_class.prepend(GraphQL::SmartSelect)

      # добавим опцию для активации плагина
      field :posts, Types::Post, null: false, smart_select: true

      # в значении мы можем, например, указать, какие поля включать всегда
      # (первичный ключ имеет смысл включать во все запросы)
      field :posts, Types::Post, null: false, smart_select: [:id]

      def posts
        Post.all
      end
    end

    class Post < GraphQL::Schema::Object
      field_class.prepend(GraphQL::SmartSelect)

      field :id, ID
      field :title, String
  
      # мы можем подсказать нашему плагину, какие поля из БД
      # нужны для формирования данного поля API
      field :contents, db_columns: [:raw_content]
      
      # для AR ассоциаций мы должны автоматически выводить
      # соответствующую колонку (внешний ключ), например, в
      # данном примере мы добавим "user_id"
      field :user, Types::User
    end
  end
end

Примечание: пример расширения API для полей смотрите в этом gist.

Инструкции по выполнению

  1. Сделать новый проект на GitHub — gem, который будет плагином для graphql-ruby.
  2. Реализовать необходимый функционал, предусмотреть нужные тесты.
  3. Прислать письмо или написать комментарий о выполненном задании.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Вова Дем Вова ДемВова Дем

Помог Михаил Рянзин Михаил РянзинМихаил Рянзин

Бэк: TestProf: добавить улучшенную поддержку сэмплирования тестов

Для уверенных в себе, задача на несколько дней

Gem test-prof включает в себя инструмент для запуска случайного набора тестов (документация).

Текущая реализация имеет ряд ограничений:

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

Необходимо усовершенстовать поддержку сэмплирования в TestProf.

Польза: узнать, как работают изнутри популярные библиотеки для тестирования в Ruby (RSpec и Minitest), принести пользу сообществу.

Инструкции по выполнению

  1. Ознакомиться с более подробным описанием задачи.
  2. Форкнуть проект test-prof на GitHub.
  3. Реализовать необходимый функционал.
  4. Сделать Pull Request.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Вова Дем Вова ДемВова Дем

Помог Андрей Кривко Андрей КривкоАндрей Кривко

Бэк: Добавить интеграцию с OptionParse в anyway_config

Для новичков, задача на неделю

Gem anyway_config предоставляет единый API для конфигурирования Ruby приложения из разных источников данных (YAML файлы, переменные окружения), позволяя без лишних усилий следовать принципам Twelve-Factor App методологии.

Необходимо добавить возможность использовать аргументы коммандной строки в качестве еще одного источника данных для конфигурации.

Для этого предполагется добавить интеграцию стандартной Ruby библиотеки OptionParse в anyway_config.

Польза: познакомится с OptionParse в Ruby, принести пользу сообществу.

Инструкции по выполнению

  1. Ознакомиться с более подробным описанием задачи.
  2. Форкнуть проект anyway_config на GitHub.
  3. Реализовать необходимый функционал.
  4. Сделать Pull Request.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Василий Стяжкин Василий СтяжкинВасилий Стяжкин

Фронт: Написать скрипт подбора правильного порядка букв алфавита Nano ID

Для новичков, задача на день

Nano ID — это очень маленькая библиотека, где идет борьба за каждый байт. Во многих файлах Nano ID есть строка алфавита. Одна из техник оптимизации — менять порядок символов в алфавите так, чтобы он повторял слова из JS-кода. Тогда gzip работает более эффективно.

Нужно написать скрипт, который бы перебирал все варианты порядка символов, чтобы найти оптимальный порядок.

Польза: получить опыт в JavaScript и оптимизации.

  1. Форкнуть Nano ID.
  2. Создать test/bruteforce. Дать ему права на исполнение. Написать в начале #!/usr/bin/env node.
  3. Скрипт будет получать имя файла аргументом командной строки: ./test/bruteforce index.js.
  4. Дальше скрипт будет читать файл и регулярным выражением находить, где в файле находится алфавит.
  5. Дальше скрипт в цикле будет менять порядок; сохранять новый файл на диск; вызывать npx size-limit FILE; парсить полученный размер в ответе Size Limit; запоминать, какой порядок символов дал минимальный размер.
  6. В конце скрипт должен записать в файл самый эффективный порядок символов алфавита.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Юлия Олецкая Юлия ОлецкаяЮлия Олецкая

Помог Дмитрий Цепелев Дмитрий ЦепелевДмитрий Цепелев

Бэк: Добавить API для поддержки различных адаптеров в Ruby gem jwt_sessions

Для уверенных в себе, задача на несколько дней

Альтернативное решение от Леонида Батижевского.

Gem jwt_sessions предоставляет базовый инструментарий для использования JWT для аутентификации пользователей.

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

Необходимо в рамках gem’а реализовать интерфейс для написания сторонних адаптеров, реализовать через него существующий Redis адаптер, а также добавить из коробки in-memory адаптер.

Польза: познакомиться поближе c JWT, применить навыки рефакторинга в Ruby, принести пользу сообществу.

Советы по реализации

Задачу можно разбить на несколько этапов.

Во-первых, нужно вынести общую логику из текущей реализации (RedisTokenStore) в абстрактный или базовый адаптер (например, AbstractTokenStore).

Во-вторых, переписать существующий RedisTokenStore с использованием абстрактного адаптера.

И, наконец, добавить новый MemoryTokenStore для хранения токенов в памяти приложения.

Также необходимо добавить параметр конфигурации, отвечающий за выбор адаптера:

JWTSessions.store_adapter = JWTSessions::RedisTokenStore.new(options)

# можно также использовать символы
JWTSessions.store_adapter = :redis, options
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Андрей Александров Андрей АлександровАндрей Александров

Фронт: Управление Grid через комментарии в Autoprefixer

Для новичков, задача на день

Autoprefixer старается конвертировать Grid Layout для Internet Explorer. Эту функцию надо явно активировать, передавая опцию grid: true.

Не у всех пользователей есть возможность выставить опции для Autoprefixer. Надо сделать включение функции с помощью комментария /* autoprefixer grid: on */.

Польза: получить опыт JavaScript в известном проекте.

  1. Форкнуть Autoprefixer.
  2. Добавить тесты.
  3. Изучить метод disabled() в Processor — он обеспечивает работу комментария /* autoprefixer: on */.
  4. На примере /* autoprefixer: on */ сделать поддержку /* autoprefixer grid: on */ везде, где в Processor используется options.grid.
  5. Добавить документацию.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Богдан Долин Богдан ДолинБогдан Долин

Фронт: Добавить предупреждения grid-area в Autoprefixer

Для новичков, задача на день

Autoprefixer старается конвертировать Grid Layout для Internet Explorer. Некоторые пользователи делают ошибку и пишут grid-area и grid-row и/или grid-column в одном и том же правиле (это бессмысленно).

Надо показывать предупреждение, если в одном правиле есть grid-area и grid-row или grid-column.

Польза: получить опыт JavaScript в известном проекте.

  1. Форкнуть Autoprefixer.
  2. Добавить тесты.
  3. Добавить код предупреждений в Processor.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог janczer janczerjanczer

Фронт: Добавить предупреждения Grid Layout в Autoprefixer

Для новичков, задача на день

Autoprefixer старается конвертировать Grid Layout для Internet Explorer. Однако свойства align-content, align-items, justify-content и justify-items нельзя сконвертировать.

Надо показывать предупреждение, если в одном правиле есть display: grid или display: inline-grid и свойства из списка выше.

Польза: получить опыт JavaScript в известном проекте.

  1. Форкнуть Autoprefixer.
  2. Добавить тесты.
  3. Добавить код предупреждений в Processor.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Дмитрий Ивлиев Дмитрий ИвлиевДмитрий Ивлиев

Бэк: Исправить реакцию на неизвестное событие в Logux Rails

Для новичков, задача на несколько дней

Logux Rails — gem, позволяющий связать Logux-сервер и приложение на Ruby on Rails. В каталоге app/logux/ разработчик описывает права доступа и контроллеры для разных типов событий от Redux и подписок.

Если разработчик не создал обработчик для какого-то события или подписки, gem выбросит ошибки NoPolicyError и NoActionError. Вместо этого нужно в ответ выдавать ['unknownAction', meta.id] или ['unknownChannel', meta.id].

Польза: получить open source портфолио в Ruby, научиться работать с Logux.

  1. Форкнуть Logux Rails.
  2. Убрать выбрасивание ошибки NoActionError. Иногда имеет смысл не иметь код в app/logux/actions для события.
  3. Для неизвестного события вместо NoPolicyError писать ['unknownAction', meta.id].
  4. Для неизвестной подписки вместо NoPolicyError писать ['unknownChannel', meta.id].
  5. Обновить тесты.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Марк Фрост Марк ФростМарк Фрост

Бэк: Добавить Logux.undo() в Logux Rails

Для новичков, задача на несколько дней

Logux Rails — gem, позволяющий связать Logux-сервер и приложение на Ruby on Rails. В каталоге app/logux/ разработчик описывает права доступа и контроллеры для разных типов событий от Redux и подписок.

Logux умеет откатить любое событие, которое было создано клиентом или отправлено с сервера. Для этого нужно сгенерировать особое событие. Нужно перенести эту логику в Rails в метод Logux.undo().

Польза: получить open source портфолио в Ruby, научиться работать с Logux.

  1. Форкнуть Logux Rails.
  2. Изучить JS-версию метода.
  3. Переписать на Ruby; this.log.add() заменить на Logux.add().
  4. Покрыть тестами.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Юрий Лебедев Юрий ЛебедевЮрий Лебедев

Бэк: Добавить rake-задачи в Logux Rails

Для новичков, задача на несколько дней

Logux Rails — gem, позволяющий связать Logux-сервер и приложение на Ruby on Rails. В каталоге app/logux/ разработчик описывает права доступа и контроллеры для разных типов событий от Redux и подписок.

Нужно добавить две rake-задачи:

  1. rake logux:actions — чтобы вывести action.type, которые ожидают все обработчики событий из app/logux/actions.
  2. rake logux:channels — чтобы вывести все подписки, которые ожидают обработчики подписок из app/logux/channels.

Польза: получить open source портфолио в Ruby, разобраться с Rake, научиться работать с Logux.

  1. Форкнуть Logux Rails.
  2. Изучить пример приложения.
  3. Найти способ собрать список всех обработчиков событий из app/logux/actions. Сгенерировать, какой action.type они ждут.
  4. Найти способ, собрать список всех обработчиков подписок из app/logux/channels. Сгенерировать, какой action.channel они ждут.
  5. Создать файл lib/rake/logux_tasks.rb.
  6. Добавить задачи logux:actions и logux:channels.
  7. Покрыть задачи тестами.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Бэк: Добавить strong params в Logux Rails

Для новичков, задача на несколько дней

Logux Rails — gem, позволяющий связать Logux-сервер и приложение на Ruby on Rails. В каталоге app/logux/ разработчик описывает права доступа и контроллеры для разных типов событий от Redux и подписок.

Нужно, чтобы в Logux::Actions работала та же фильтрация входящих параметров, что и в контроллерах Rails.

Польза: получить open source портфолио в Ruby, научиться работать с Logux.

  1. Форкнуть Logux Rails.
  2. Прочитать про strong params: причины, документацию, API.
  3. Разобраться, как strong params подключаются к контроллерам Rails.
  4. Подключить их так же в Logux::Actions.
  5. Покрыть тестами.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Андрей Падерин Андрей ПадеринАндрей Падерин

Бэк: Улучшить логер в Logux Rails

Для новичков, задача на несколько дней

Logux Rails — gem, позволяющий связать Logux-сервер и приложение на Ruby on Rails. В каталоге app/logux/ разработчик описывает права доступа и контроллеры для разных типов событий от Redux и подписок.

Нужно улучшить вывод gem’а в консоль согласно списку в issue.

Польза: получить open source портфолио в Ruby, опыт работы с логером в Rails, научиться работать с Logux.

  1. Форкнуть Logux Rails.
  2. Изучить список улучшений.
  3. Изучить, как в Rails принято подсвечивать вывод в консоли.
  4. Найти подсветку синтаксиса для JSON.
  5. Улучшить вывод.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Дмитрий Топорнин Дмитрий ТопорнинДмитрий Топорнин

Бэк: Генерировать meta.id в Logux Rails

Для новичков, задача на несколько дней

Logux Rails — gem, позволяющий связать Logux-сервер и приложение на Ruby on Rails. В каталоге app/logux/ разработчик описывает права доступа и контроллеры для разных типов событий от Redux и подписок.

Каждое событие в Logux имеет уникальный ID в meta.id. Но пока Logux Rails не умеет генерировать этот ID.

Польза: получить open source портфолио в Ruby, научиться работать с Logux.

  1. Форкнуть Logux Rails.
  2. Изучить JS-версию генератора ID.
  3. При старте сервера сгенерировать уникальный node_id вида server:#{ nanoid(8) }.
  4. При генерации события в Logux.add() ставить ему meta.id.
  5. Покрыть тестами.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог ojab ojabojab

Бэк: Улучшить ответ при ошибке в Logux Rails

Для новичков, задача на несколько дней

Logux Rails — gem, позволяющий связать Logux-сервер и приложение на Ruby on Rails. В каталоге app/logux/ разработчик описывает права доступа и контроллеры для разных типов событий от Redux и подписок.

Сейчас при ошибке gem всегда выдает ['error'] в ответ. Нужно возвращать ['error', meta.id, error_stack] или ['error', auth_id, error_stack].

Польза: получить open source портфолио в Ruby, научиться работать с Logux.

  1. Форкнуть Logux Rails.
  2. Изучить текий способ обработки ошибок.
  3. Изменить обработку ошибок, чтобы знать, какая команда из command_params вызвала ошибку.
  4. Для ошибки во время команды action нужно писать в ответ ['error', meta.id, error_stack].
  5. Для ошибки во время команды auth нужно писать в ответ ['error', chunk.auth_id, e.backtrace.join("\n")].
  6. Убедиться, что ошибка в одной команде не мешает обработать остальные команды.
  7. Обновить тесты.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Вова Дем Вова ДемВова Дем

Помог Дмитрий Цепелев Дмитрий ЦепелевДмитрий Цепелев

Бэк: ActiveRecord: ленивая предзагрузка ассоциаций

Для уверенных в себе, задача на несколько дней

PR в Rails от Глеба Иванова.

В ActiveRecord предусмотрено несколько методов для предварительной загрузки ассоциированных записей (такие как includes, eager_load и другие). Это позволяет выгружать данные, избегая так называемой проблемы N+1 запросов.

В некоторых случаях мы не знаем заранее, какие ассоциации нам понадобятся при выполнении запроса (простой пример — работа с GraphQL).

Приходится либо предзагружать лишние данные (например, указывая все ассоциации в includes), либо использовать альтернативные подходы, такие как batch loading.

Необходимо написать ленивую реализацию метода preload, которая предзагружает ассоциации только если они используются.

Польза: детально узнать, как работает Rails и ActiveRecord изнутри, принести пользу Rails-сообществу.

Пример работы

class User < ApplicationRecord
  has_many :posts
end

class Post < ApplicationRecord
  has_many :comments
  belongs_to :user
end

class Comment < ApplicationRecord
  belongs_to :user
  belongs_to :post
end

# Инициируем выборку: выгружаем пользователей с публикациями,
# комментариями и авторами комментариев
users = User.lazy_preload(posts: { comments: :user } ).limit(10)

# Будет выполнен один запрос
#=> SELECT * FROM users LIMIT 10
users.each do |user|
  # Запрос на загрузку постов будет выполнен при первом
  # обращении к ассоциации на любом пользователе,
  # но записи будут загружены сразу для всех пользователей
  #
  # SELECT * FROM posts WHERE user_id in (...)
  user.posts.each do |post|
    p post.title
  end
end

# Комментарии не будет предзагружены, так как мы к ним не обращались.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Юрий Тимофеев Юрий ТимофеевЮрий Тимофеев

Фронт: Создать nanoid-good, nanoid с фильтром обсценных слов

Для новичков, задача на день

Nano ID генерирует случайные ID. Так как идентификаторы полностью случайные, частью буквенно-цифрового идентификатора может стать обсценное слово.

Нужно создать nanoid-good, который будет проверять ID на плохие слова и, если надо, генерировать ID еще раз.

Польза: получить больше опыта в JavaScript и пополнить open-source портфолио.

  1. Найти самый полный словарь на npm. Желательно, чтобы там были не только английские слова. Если найти не получается, то можно выложить на npm этот список.
  2. Создать новый npm-проект с именем nanoid-good. Не публиковать его, пока Ситник не проверит.
  3. Указать nanoid в зависимостях.
  4. Сделать index.js, где будет функция, принимающая те же аргументы, что nanoid, но возвращающая ID без обсценных слов.
  5. Сделать non-secure.js, где будет такая же логика, как и в index.js, но будет использоваться nanoid/non-secure.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Даниил Шашков Даниил ШашковДаниил Шашков

Фронт: Перевести yaspeller на cosmiconfig

Для новичков, задача на день

Сейчас yaspeller берет свои настройки только из файла .yaspellerrc. Хотелось бы, чтобы он поддерживал поле "yaspeller" в package.json, как многие остальные инструменты из npm.

Чтобы не писать много кода поиска настроек, можно использовать библиотеку cosmiconfig.

Польза: получить больше опыта в JavaScript.

  1. Форкнуть yaspeller.
  2. Перевести поиск файла настроек на cosmiconfig. На этом этапе искать только файл .yaspellerrc.
  3. Добавить тесты на поле "yaspeller" в package.json и добавить поиск его в cosmiconfig.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Долганов Сергей Долганов СергейДолганов Сергей

Помог Меркушин Михаил Меркушин МихаилМеркушин Михаил

Бэк: Гемизация «простейших контрактов» на Ruby

Для продвинутых, задача на неделю

Контракт — это набор валидаций (тестов), которые запускаются во время production сессии взаимодействия с внешней системой по API (например, CRM системой или социальными сетями).

Такие валидации решают проблему упрощения отладки и распознавания отклонений в поведении внешних зависимостей. Пример реализации — poro_contract.

Нужно создать новый gem (назовем его simple_contracts), который:

  1. внутри работает по таким же принципам, как POROContract, или просто оборачивает его в gem;
  2. является самой простой реализацией «контрактов» на Ruby в виде gem с минимумом зависимостей;
  3. обладает способностью прогонять проверку «контракта» параллельно, не влияя на основной поток исполнения (в случае использования IO в теле контракта).

Польза: получить отличный опыт с многопоточным программированием в Ruby; освоить контрактный подход к тестированию API.

Постановка задачи

Базовый контракт реализован в poro_contract. К сожалению, это не gem и там не хватает одного важного куска.

На практике мы столкнулись со следующей проблемой. Пусть в приложении реализован клиент к разным социальным сетям (Twitter, Facebook, VK) и публикация идет от имени официальной страницы или группы. Нужно обезопасить себя от ошибочных публикаций, поэтому в приложении добавлена возможность удалить пост из всех социальных сетей. И только через месяц после очередного такого удаления разработчик может узнать, что социальная сеть иногда не удаляет пост на самом деле, хотя вызов API и ответ от API был корректным.

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

# SimpleContract - should not support #match_async!
# SimpleContract[:parallel] - marks that inherited Contract, should be thread-safe and could run in parallel with #match_async!
class TwitterContract < SimpleContract[:parallel]
  # ... other rules

  def guarantee_verified_delete
    return true if @request.path !~ %r{statuses/destroy}
    return true if Twitter::REST::Client.new(@credentials).statuses(@post.tweet_id).empty?
    false
  end
end

# Use synchronously, (raises exception, "Fails Fast"™):
@post = Post.find(params[:post_id])
TwitterContract.new.match! { response = TwitterAPI.destroy(@post) }

# Use asynchronously, (does not affect TwitterAPI.destroy, but tracks any problems with TwitterContract validation):
TwitterContract.match_async! { response = TwitterAPI.destroy(@post) }

Советы по реализации

Архитектурных решений видится несколько:

  • распараллеливать всю проверку контракта;
  • распараллеливать только отдельные правила, содержащие IO.

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

На что обратить внимание:

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

Инструкции по выполнению

  1. Посмотреть реализацию и пример использования контрактов poro_contract.
  2. Завернуть решение в новый гем (например, simple_contracts) и покрыть тестами.
  3. Продумать архитектурное решение для контрактов с IO операциями.
  4. Создать pull request с обоснованием и реализацией асинхронной проверки контракта.
  5. Покрыть новую функциональность тестами.

P.S.: Есть еще gem blood_contracts — в нем параллельное выполнение работает ненадежно, поэтому ориентироваться на него не стоит. BloodContracts позиционируется как gem более сложно устроенный, a la “Rails for Contracts”. Поэтому simple_contracts должен в плане простоты быть его антиподом.

Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Даниил Шашков Даниил ШашковДаниил Шашков

Фронт: Перевести shortid на nanoid

Для новичков, задача на неделю

shortid использует опасные методы генерации ID. К сожалению, его использует уже слишком много проектов. Поэтому надо заменить в нем метод генерации ID, сохранив прежний API.

Польза: получить больше опыта в JS.

  1. Форкнуть shortid.
  2. Поключить в зависимости nanoid.
  3. Переписать методы генерации, чтобы он использовал nanoid/generate, вместо собственного алгоритма перестановки алфавита.
  4. Проверить, что все старые тесты проходят.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Даниил Шашков Даниил ШашковДаниил Шашков

Фронт: Создать инструмент clean-publish

Для продвинутых, задача на неделю

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

Можно держать все эти настройки в отдельных файлах — тогда в папке проекта будет много файлов. Например, из-за длинного списка файлов README на GitHub будет далеко после большого списка файлов.

Можно перенести настройки в package.json, но тогда они окажутся в npm-пакете, что увеличит его размер.

Можно решить проблему, если создать инструмент clean-publish. Он будет копировать файлы проекта во временную папку, убирать лишнее из package.json и вызывать npm publish на временной папке.

Польза: получить больше опыта в JavaScript.

  1. Создать новый npm-проект с именем clean-publish.
  2. В проекте надо создать исполняемый файл clean-publish.js и прописать его в поле bin в package.json.
  3. В пакете будет список ненужных полей из package.json. Например, eslintConfig и jest. Также можно убирать devDependencies и все scripts кроме нужных для npm (например, postinstall).
  4. Можно добавить опцию, чтобы указывать дополнительные поля для удаления.
  5. Нужно убедиться, что при вызове npm publish его цветной вывод идет в вывод clean-publish.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Иван Малов Иван МаловИван Малов

Фронт: Исправить вложенные медиа-выражения в Autoprefixer Grid

Для новичков, задача на день

В некоторых случаях Autoprefixer генерирует вложенные медиа-выражения. В этих случаях надо объединять медиа-выражения в одно.

@media (min-width: 30em) {
  .wrapper {
    display: grid;
    grid-template-areas: "a b";
  }
}

@media (min-width: 60em) {
  .wrapper {
    grid-template-areas: "a b";
  }
}

@media (min-width: 30em) {
  .a {
    grid-area: a;
  }
}

@media (min-width: 30em) {
  .b {
    grid-area: b;
  }
}

Польза: указать в резюме коммит в известный проект.

  1. Форкнуть Autoprefixer.
  2. Добавить случай в тесты.
  3. Исправить код генерации Grid.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Богдан Долин Богдан ДолинБогдан Долин

Фронт: Предупреждать о конфликте имен областей в Autoprefixer Grid

Для новичков, задача на день

Autoprefixer умеет генерировать префиксы для Grid Layout только если имена областей уникальные. Например, в этом случае сгенерировать префиксы нельзя:

.parent-alpha {
  grid-template-areas: "delta  echo";
}

.parent-beta {
  grid-template-areas: "echo  delta";
}

.grid-cell {
  -ms-grid-column: ???; /* не понятно, от какого родителя брать местоположение */
  arid-area: echo;
}

В этих случаях надо выводить предупреждение.

Польза: указать в резюме коммит в известный проект.

  1. Форкнуть Autoprefixer.
  2. Добавить случай в тесты.
  3. Добавить предупреждение, когда такой случай обнаружен.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помогла Аня Кирюхина Аня КирюхинаАня Кирюхина

Фронт: Ускорить токенайзер PostCSS

Для уверенных в себе, задача на неделю

В хороших парсерах разбор разбит на два шага: строка → токены и токены → дерево объектов. Первый шаг называется токенайзер.

Сейчас токенайзер возвращает [token_name, content, start_line, start_column, end_line, end_column]. Есть мнение, что можно сильно ускорить токенайзер, если:

  1. Возвращать Uint32Array(token_code, offset_start, offset_end, start_line, start_column, end_line, end_column). То есть, вместо строки с именем токена использовать цифровой код. А content парсер может взять сам из строки входящего CSS по offset_start и offset_end.
  2. Если токенайзер будет использовать один и тот же экземпляр Uint32Array. В итоге не будет постоянно создаваться больше объектов и вызываться сборщик мусора.

Польза: указать в резюме коммит в известный проект.

  1. Загрузить бенчмарк.
  2. Форкнуть PostCSS.
  3. Переключиться на ветку amy в PostCSS.
  4. Исправить код токенайзера и парсера.
  5. Вызвать gulp build в PostCSS и потом gulp tokenizers в бенчмарке.
  6. Вне зависимости от результата отправить PR с результатами бенчмарка.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Вова Дем Вова ДемВова Дем

Помог

Бэк: TestProf: поддержка трейтов в FactoryDefault

Для новичков, задача на день

FactoryDefault – это один из инструментов, входящих в состав TestProf.

Он позволяет переиспользовать уже созданные фабрикой объекты для вложенных ассоциаций, решая таким образом проблему каскадов фабрик.

Необходимо сделать так, чтобы FactoryDefault учитывал используемые при создании ассоциаций трейты.

Польза: узнать, как работает FactoryGirl изнутри, принести пользу сообществу.

Инструкции по выполнению

  1. Ознакомиться с более подробным описанием задачи.
  2. Форкнуть проект test-prof на GitHub.
  3. Реализовать необходимый функционал.
  4. Сделать Pull Request.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Евгений Петухов Евгений ПетуховЕвгений Петухов

Фронт: Исправить логику вставки row/column в Автопрефиксере

Для новичков, задача на неделю

Autoprefixer умеет вставлять префиксы Grid Layout для Internet Explorer. Поддерживается даже grid-template-areas.

Но, в некоторых случаях, префиксы для grid-template-areas в медиа-выражении могут быть вставлены не в том месте. Нужно изменить логику.

Польза: указать в резюме коммит в известный проект.

Сейчас для кода

.grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-template-areas: "a   b"
                       "c   d";
}
@media (min-width: 600px) {
  .grid {
    grid-template-areas: "a   b   c   d";
  }
}
.grid__cell--a {
  grid-area: a;
}

Autoprefixer сгенерирует:

.grid {
  display: -ms-grid;
  display: grid;
  -ms-grid-columns: (1fr)[2];
  grid-template-columns: repeat(2, 1fr);
  grid-template-areas: "a   b"
                       "c   d";
}
@media (min-width: 600px) {
  .grid {
    grid-template-areas: "a   b   c   d";
  }
  .grid__cell--a {
    -ms-grid-row: 1;
    -ms-grid-column: 1;
  }
}
.grid__cell--a {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
  grid-area: a;
}

В итоге, код будет работать неправильно, так как второй .grid__cell--a (вне @media) перезапишет значение первого. Правильный вариант:

.grid {
  display: -ms-grid;
  display: grid;
  -ms-grid-columns: (1fr)[2];
  grid-template-columns: repeat(2, 1fr);
  grid-template-areas: "a   b"
                       "c   d";
}
@media (min-width: 600px) {
  .grid {
    grid-template-areas: "a   b   c   d";
  }
}
.grid__cell--a {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
  grid-area: a;
}
@media (min-width: 600px) {
  .grid__cell--a {
    -ms-grid-row: 1;
    -ms-grid-column: 1;
  }
}
  1. Форкнуть Автопрефиксер.
  2. Поправить или добавить тесты в файлах в test/cases/grid-template-*.
  3. Изменить логику insertAreas.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Антон Тужик Антон ТужикАнтон Тужик

Фронт: Предупреждать об устаревшем caniuse-lite в Browserslist

Для новичков, задача на неделю

Многие пользователи Autoprefixer и Babel забывают обновлять базу браузеров caniuse-lite. В этой базе есть информация о времени релиза каждой версии браузера. Взяв дату самой свежей версии браузера, можно примерно узнать время релиза caniuse-lite. Если база не обновлялась уже полгода, надо показать предупреждение пользователю.

Польза: указать в резюме коммит в известный проект.

  1. Форкнуть Browserslist.
  2. При инициализации node.js найти самый свежий браузер из caniuse-lite. Сравнить время релиза с текущим временем. Вывести предупреждение, если разница больше полугода.
  3. Продумать текст предупреждения. По тексту должно быть понятно, что это предупреждение из Browserslist, и должно быть понятно написано, как обновить caniuse-lite (и для npm, и для yarn — в зависимости от наличия yarn.lock рядом с package.json).
  4. Добавить тесты.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Станислав Ботев Станислав БотевСтанислав Ботев

Фронт: Добавить правило про reduced-motion в Stylelint

Для новичков, задача на неделю

Некоторым пользователям не нравится, когда на странице много анимаций. В Safari есть специальное медиа-выражение @media (prefers-reduced-motion) { }. Если пользователь не хочет анимаций, Safari будет его применять.

Но большинство фронтенд-разработчиков про него забывают. Эту проблему может решить новое правило для Stylelint.

Польза: указать в резюме коммит в известный проект.

  1. Форкнуть Stylelint.
  2. Прочитать, как писать правила для Stylelint.
  3. Прочитать про prefers-reduced-motion.
  4. Добавить новое правило, которое ищет все селекторы с transition или animation и проверяет, что такой же селектор есть внутри @media (prefers-reduced-motion) { }.
  5. Добавить тесты, документацию и все остальное согласно правилам Stylelint.
  6. Создать pull request. Внимательно заполнить их шаблон. Не указывать предыдущий issue, раз они обиделись на автора идеи. Расписать по каждому пункту из критериев, почему правило нужно включить в ядро.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Станислав Ботев Станислав БотевСтанислав Ботев

Фронт: Добавить проверку наличия :focus в Stylelint

Для новичков, задача на неделю

Многие пользователи пользуются сайтами с клавиатуры; у некоторых даже нет другой возможности. Но большинство фронтенд-разработчиков забывают указать :focus стили.

Эту проблему можно уменьшить, если добавить в Stylelint правило, которое будет напоминать разработчику писать :focus стиль.

Чтобы понять, каким элементам нужен :focus, можно использовать стили :hover. Можно считать, что всем стилям с :hover, нужен какой-то парный стиль с :focus.

Польза: указать в резюме коммит в известный проект.

  1. Форкнуть Stylelint.
  2. Прочитать, как писать правила для Stylelint.
  3. Добавить новое правило.
  4. Учесть и .some:hover { } .some:focus { }, и .some:hover, .some:focus { }.
  5. Добавить тесты, документацию и все остальное, согласно правилам Stylelint.
  6. Создать pull request. Не указывать предыдущий issue, раз они обиделись на автора идеи. Расписать по каждому пункту из критериев, почему правило нужно включить в ядро.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Даниил Северин Даниил СеверинДаниил Северин

Фронт: Сделать хороший дизайн главной страницы postcss-preset-env

Для новичков, задача на неделю

Скоро postcss-preset-env заменит cssnext и станет одним из «главных» плагинов PostCSS.

У плагина есть сайт, но его главная страница совсем не информативная.

Задача подойдет, если вы больше фокусируетесь на дизайне и CSS.

Польза: указать в резюме коммит в известный проект.

  1. Форкнуть репозиторий сайта.
  2. Переключиться в ветку jonathantneal.
  3. Подумать, как кратко объяснить, о чем этот плагин, чем он лучше cssnext, чем он может быть полезен разработчикам. Отдельно можно сравнить его с некоторыми функциями Sass и провести ассоциацию с CoffeeScript и Babel.
  4. Если есть вопросы по тому, как лучше рассказать о плагине или чем он лучше — спросить в чате PostCSS или лично Ситника.
  5. Добавить больше примеров и текста на главную.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Павел Винник Павел ВинникПавел Винник

Фронт: Добавить postcss-preset-env на сайт PostCSS

Для новичков, задача на неделю

Скоро postcss-preset-env заменит cssnext и станет одним из «главных» плагинов PostCSS. Но на сайте PostCSS мы все еще рекомендуем cssnext.

Задача подойдет, если вы больше фокусируетесь на дизайне и CSS, но хотите получить больше опыта с React.

Польза: указать в резюме коммит в известный проект.

  1. Форкнуть репозиторий сайта.
  2. Подумать, какой логотип взять для postcss-preset-env. Как вариант, можно взять логотип cssdb.
  3. Заменить cssnext на postcss-preset-env.
  4. Обновить пример. Убрать Custom Properties. Показать использование color-mod() и Custom Media.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Сергей Карапетян Сергей КарапетянСергей Карапетян

Фронт: Починить работу со Custom Properties в cssnano

Для новичков, задача на неделю

cssnano сжимает CSS и используется по умолчанию в webpack. Эта задача поможет с выпуском cssnano 4.

Сейчас cssnano, встретив padding: 10px; padding: var(--name), удалит первое свойство. Надо исправить это поведение.

Польза: указать в резюме коммит в известный проект.

  1. Изучить ошибку.
  2. Форкнуть cssnano.
  3. Изучить плагин mergeLonghand.
  4. Добавить особую проверку и не удалять дублирующее свойство, если только в одном из свойств используются переменные.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Евгений Грачев Евгений ГрачевЕвгений Грачев

Фронт: Починить работу с -ms-input-placeholder в cssnano

Для новичков, задача на неделю

cssnano сжимает CSS и используется по умолчанию в webpack. Эта задача поможет с выпуском cssnano 4.

Сейчас cssnano, встретив :-ms-input-placeholder {} ::-ms-input-placeholder { }, объединит правила в :-ms-input-placeholder, ::-ms-input-placeholder { }. К сожалению, это ломает поддержку Internet Explorer.

Польза: указать в резюме коммит в известный проект.

  1. Изучить ошибку.
  2. Форкнуть cssnano.
  3. Изучить плагин mergeRules.
  4. Добавить особую проверку и не объединять правила с -ms-input-placeholder в обоих селекторах.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Evilebot Tnawi Evilebot TnawiEvilebot Tnawi

Фронт: Починить mergeLonghand в cssnano

Для уверенных в себе, задача на неделю

cssnano сжимает CSS и используется по умолчанию в webpack. Эта задача поможет с выпуском cssnano 4.

Правило mergeLonghand иногда работает неправильно. Надо изучить его и починить.

Польза: указать в резюме коммит в известный проект.

  1. Изучить ошибку.
  2. Форкнуть cssnano.
  3. Изучить плагин mergeLonghand.
  4. Изменить логику.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Влад Янчевский Влад ЯнчевскийВлад Янчевский

Фронт: Починить работу с initial в cssnano

Для новичков, задача на неделю

cssnano сжимает CSS и используется по умолчанию в webpack. Эта задача поможет с выпуском cssnano 4.

Сейчас cssnano, встретив:

.a { all: initial; color: red }
.b { all: initial; color: blue }

может превратить свойства в:

.a { color: red }
.a, .b { all: initial; color: red }
.b { color: blue }

В итоге правило будет работать неправильно.

Польза: указать в резюме коммит в известный проект.

  1. Изучить ошибку.
  2. Форкнуть cssnano.
  3. Изучить плагин mergeRules.
  4. Добавить особую проверку и не размещать правила выше all: initial.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Игорь Уваров Игорь УваровИгорь Уваров

Фронт: Починить работу со шрифтами в cssnano

Для новичков, задача на неделю

cssnano сжимает CSS и используется по умолчанию в webpack. Эта задача поможет с выпуском cssnano 4.

Нужно разобраться с ошибкой шрифтов.

Польза: указать в резюме коммит в известный проект.

  1. Изучить ошибку.
  2. Форкнуть cssnano.
  3. Попробовать повторить ошибку.
  4. Исправить ошибку.
  5. Желательно добавить тесты, чтобы ошибка не вернулась в будущем.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Evilebot Tnawi Evilebot TnawiEvilebot Tnawi

Фронт: Обновить зависимости в cssnano

Для новичков, задача на неделю

cssnano сжимает CSS и используется по умолчанию в webpack. Эта задача поможет с выпуском cssnano 4.

Надо обновить зависимости и API.

Польза: указать в резюме коммит в известный проект.

  1. Усатновить yarn.
  2. Форкнуть cssnano.
  3. Выполнить yarn upgrade-interactive --latest в проекте.
  4. Прочитать, что нового для каждого проекта с мажорным обновлениеем (обновлением первого номера версии).
  5. Исправить код, если API зависимости изменился.
  6. Проверить, что тесты работают.
  7. Выполнить yarn upgrade.
  8. Проверить, что тесты работают.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Павел Востриков Павел ВостриковПавел Востриков

Фронт: Добавить поддержку игнорирования следующей строки в Autoprefixer

Для новичков, задача на неделю

Сейчас Autoprefixer понимает особые комментарии /* autoprefixer: off */ и /* autoprefixer: on */, которые выключают или включают его на весь блок стилей.

Нужно добавить поддержку комментария /* autoprefixer: ignore next */, чтобы Autoprefixer игнорировал только следующее свойство или правило.

Польза: указать в резюме коммит в известный проект.

  1. Форкнуть Autoprefixer.
  2. Добавить поддержку комментария для добавления и для удаления правил.
  3. Добавить поддержку комментария для добавления и для удаления свойств.
  4. Добавить поддержку комментария для добавления и для удаления директив.
  5. Добавить тесты.
  6. Добавить документацию в раздел Control Comments.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Павел Востриков Павел ВостриковПавел Востриков

Фронт: Добавить выбор версий Node.js в Browserslist

Для новичков, задача на неделю

Browserslist — общий конфиг списка браузеров для Autoprefixer, Babel и других front-end инструментов. В конфиге разработчики пишут запросы вида last 2 versions, Browserslist переводит это в список конкретных версий браузеров.

Но для Babel и ESLint нужно указывать не только браузеры, но и версии Node.js.

Польза: указать в резюме коммит в проект с 20 млн. загрузок в месяц.

  1. Форкнуть Browserslist.
  2. Добавить в зависимости node-releases.
  3. Добавить поддержку запроса browserslist('node 9.11.1') => ['node 9.11.0'] и тесты для него.
  4. Добавить поддержку запроса node 9.11, загружающий node 9.11.1.
  5. Добавить поддержку запроса node 9, загружающий node 9.11.1.
  6. Добавить поддержку запроса maintained node versions, возращающий все поддерживаемые в данный момент версии.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Сергей Лысенко Сергей ЛысенкоСергей Лысенко

Фронт: Добавить поддержку color-adjust в Автопрефиксер

Для новичков, задача на неделю

CSS-свойство color-adjust из черновика CSSWD работает в webkit-браузерах через свойство -webkit-print-color-adjust.

Нужно добавить поддержку этого свойства в Автопрефиксер.

Польза: написать в резюме, что сделали минорный релиз Автопрефиксера.

  1. Прочитать о -webkit-print-color-adjust и color-adjust. Узнать, кто их поддерживает и, примерно, с какой версии. Начальные ссылки есть в issue Автопрефиксера.
  2. Послать PR в caniuse с данными о префиксах и поддержке разными браузерами. В конце PR написать /cc @ai.
  3. Форкнуть Автопрефиксер.
  4. Добавить даннные в data/prefixes.js.
  5. Добавить новый хак в lib/hacks/. Сделать в нем замену имени свойства по примерам других хаков.
  6. Загрузить новый хак в lib/prefixes.js.
  7. Добавить тестовые CSS в test/cases/.
  8. Добавить тест использующий эти тестовые CSS в test/autoprefixer.test.js.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Бэк: Добавить новые источники данных в Ossert: Twitter

Для уверенных в себе, задача на несколько дней

Нужно добавить в Ossert новые источники данных. Отличным кандидадатом с достаточно богатым API является Twitter.

Это позволит измерить еще один важный аспект развития Open-Source библиотек — хайп, реакцию на посты про проект, а также количество заинтересованных проектом.

Польза: возможность научиться работать с API Twitter, написать надежный API клиент и узнать больше о метриках и поведении разработчиков свободного ПО.

Как это должно работать?

Сейчас сбор информации уже работает для RubyGems, GitHub, Bestgems и StackOverflow. Нужно совместимым образом организовать сбор с новых источников.

Кейс с Twitter представляет особую сложность, так как поиск по истории твитов доступен только на 7 дней назад. Таким образом, это будет первый источник данных с инкрементальным сбором. То есть, нужно побороть возможность утраты уже накопленных данных.

Также, стоит отметить, что у Twitter API нет схемы, так что придется продумать валидации исходящих и распознавание получаемых данных.

Советы по реализации

module Ossert
  module Fetch
    class Twitter
      def initialize(project)
        ...
      end

      def process
        # Метод сбора основных метрик по проекту
      end
    end
  end
end

Для этого нужно проанализировать возможность API вашего источника данных и выбрать:

  1. параметры для сбора;
  2. полезные метрики, которые можно измерить на их основании.

Рекомендации:

  • Собрать охват по постам с URL проекта на GitHub или по строке "<author>/<project name>"
  • Охват (количество пользователей, которые увидели информацию) = количество твитов о геме * подписчиков авторов твитов + количество ретвитов оригинальных твитов * подписчиков ретвитеров
  • Количество ретвитов/лайков/комментариев по постам о проекте

У нас нет возможности собрать полную историю по запросам API, поэтому предлагается для всех метрик Twitter использовать Moving Average за семь дней. То есть, мы каждый день собираем данные за последние 7 дней и считаем среднее значение (с пересечением усредняемых данных).

В Ossert данные выводятся по кварталам, так что для Twitter потребуется как минимум отдельный способ хранения.

Также неизвестными являются ограничения на количество запросов, хотя надо продумать как сделать возможной синхронизацию более чем 100K гемов.

Бонус

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

Инструкции по выполнению

  1. Форкнуть проект Ossert на GitHub.
  2. Реализовать необходимый функционал.
  3. Сделать Pull Request.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Алексей Комаров Алексей КомаровАлексей Комаров

Фронт: Сделать калькулятор вероятность коллизии NanoID

Для новичков, задача на неделю

NanoID — JavaScript-библиотека для генерации случайных ID. Как и у UUID, есть определенная вероятность того, что будет сгенерированы два одинаковых ID.

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

Польза: получить опыт JS-разработки; получить публичный сайт в свое резюме.

  1. Изучить, как нужно считать вероятность генерации одинаковых ID и количество случайных бит.
  2. Сделать статичную страницу, где у пользователя будет спрашиваться длина ID, сколько ID генерируется в час, алфавит. В итоге будет выводиться, как много лет пройдет перед тем, как вероятность получить одинаковый ID в двух документах будет больше, чем 1%.
  3. При загрузке страницы эти поля должны быть сразу заполнены какими-то стандартными данными (длина и алфавит по умолчанию для NanoID, 1000 ID в час).
  4. Добавить на страницу краткое описание NanoID и описание того, что делает калькулятор.
  5. Добавить пример кода: как генерировать ID в NanoID с выбранным алфавитом и длиной. Если алфавит стандартный, нужно использовать require('nanoid'), для нестандартного — require('nanoid/generate').
  6. Постараться сделать страницу красиво. Указать межстрочный интервал, выбрать шрифт, выделить главное.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Бэк: Isolator: инструмент для отслеживания побочных эффектов внутри транзакций БД

Для продвинутых, задача на неделю

Необходимо написать инструмент для Ruby-стека, который будет отслеживать выполнение потенциально опасных действий внутри транзакции БД (например, HTTP-запросов или отправки фоновых задач в очередь).

Польза: разобраться в том, как работают популярные ORM и другие библиотеки для работы с «внешним миром»; написать инструмент, которым будет активно пользоваться Ruby-сообщество.

Постановка задачи

Основная задача — подсказать разработчику, что внутри транзакции выполняется какая-то небезопасная операция.

Например:

# вызов HTTP
User.transaction do
  user = User.new(user_params)
  user.save!
  # происходит вызов внешнего API
  PaymentsService.charge!(user)
end

# создание фоновой задачи
User.transaction do
  user.update!(confirmed_at: Time.now)
  UserMailer.successful_confirmation(user).deliver_later
end

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

Что именно отслеживать?

  • HTTP вызовы (посмотрите на sniffer)
  • Отправка в очередь фоновых задач (но только в том случае, когда для хранения очереди используется не БД)
  • Что еще? Все перечислить невозможно, поэтому необходимо предусмотреть интерфейс/инструкцию для расширения (регистрации произвольных проверок)

Как уведомлять?

Isolator должен уметь уведомлять об ошибках разными способами:

  • выбрасывать исключения (удобно при разработке и тестировании)
  • при использовании в стейджинг-окружении нужно иметь возможность посылать уведомления во внешний мир (например, через uniform_notifier)

Внимание: при использовании в тестовом окружении необходимо учесть, что тесты могут выполнятся внутри транзакции (use_transaction_tests в Rails). В этом случае мы должны игнорировать «внешнюю», тестовую транзакцию.

Советы по реализации

  • Необходимо предусмотреть работу с различными ORM адаптерами (начать можно с ActiveRecord).
  • Подключение должно быть максимально простым и не требовать явного указания, с каким ORM интегрироваться — то есть, достаточно просто сделать require "isolator" (или добавить в Gemfile).
  • Сообщение об ошибке должно указывать, где именно вызывается опасный метод в приложении; также было бы полезно показывать, где была инициирована транзакция.

Инструкции по выполнению

  1. Форкнуть проект isolator на GitHub.
  2. Реализовать необходимый функционал.
  3. Сделать Pull Request.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Кирилл Кузнецов Кирилл КузнецовКирилл Кузнецов

Бэк: Добавить поддержку Chef Client 13 в кукбук для управления БД PostgreSQL: postgresql_lwrp

Для продвинутых, задача на пару дней

postgresql_lwrp — самый удобный и гибкий кукбук для системы управления конфигурациями Chef, обеспечивающий установку и настройку БД PostgreSQL.

Нужно обеспечить его работу в Chef Client версии 13.

Польза: возможность попрактиковаться в написании кукбуков Chef, разобраться в особенностях Chef 13.

Этот кукбук создавался и активно развивался в период, когда самой свежей версией Chef client была 12-я. Релиз 13-й версии принес много нововведений, в том числе ломающих совместимость. Необходимо обновить код кукбука с учетом этих нововведений.

В процессе работы потребуется разобраться со списком сторонних кукбуков, от которых зависит postgresql_lwrp. Возможно, потребуется их замена или полный рефакторинг соответствующих мест, так как они тоже могут быть несовместимы с Chef Client 13.

Может быть удобнее выполнять задание, если сразу сделать отдельные Test Kitchen suites, использующие свежий Chef Client 13. Test Kitchen suites для Chef Сlient 12 стоит сохранить, чтобы проверять обратную совместимость: 12-я версия все еще активно используется в старых инсталляциях.

Что нужно сделать:

  1. Форкнуть наш форк или оригинальный репозиторий от Express 42 кукбука на GitHub.
  2. Реализовать необходимый функционал.
  3. Добавить новые тесты.
  4. Сделать Pull Request.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Дерябин Андрей ДерябинАндрей Дерябин

Помог Михаил Мандронов Михаил МандроновМихаил Мандронов

Бэк: Поддержка Excon для Sniffer

Для новичков, задача на пару дней

Sniffer – это гем для логирования и анализа HTTP-траффика, который поддерживает большинство ruby-библиотек для работы с HTTP-запросами.

Hеобходимо добавить поддержку Excon.

Польза: получить опыт разработки gem’ов, разобраться в принципах работы с HTTP-запросами в Ruby, помочь полезному проекту

Что нужно сделать:

  1. Форкнуть проект Sniffer на GitHub.
  2. Реализовать необходимый функционал.
  3. Написать тесты.
  4. Сделать Pull Request.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Владимир Боровик Владимир БоровикВладимир Боровик

Фронт: Добравить поддержку конфига в Size Limit

Для новичков, задача на неделю

Прямо сейчас Size Limit читает свои настройки из package.json. Но было бы хорошо добавить поддержку отдельного файла настроек, например, .size-limit с JSON внутри.

Польза: получить больше опыта работы с Node.js.

  1. Изучить cosmiconfig. Понять, подходит ли он для задачи.
  2. Форкнуть size-limit.
  3. Исправить ./cli.js для использования с cosmiconfig (или написать код поиска файла настроек самому, если cosmiconfig не подходит).
  4. Добавить тесты.
  5. Добавить документацию.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Игорь Дерябин Игорь ДерябинИгорь Дерябин

Фронт: Добравить запрос по году релиза в Browserslist

Для новичков, задача на неделю

Browserslist — инструмент для Autoprefixer и Babel для выбора браузеров, которые нужно поддерживать в проекте.

Есть хорошая идея добавить запрос вида since 2013 для выбора версий браузеров, вышедших с 2003 года.

Польза: принять участие в проекте с 11 млн. загрузок.

  1. Форкнуть caniuse-lite.
  2. Добавить в src/packer/agents.js копирование release_date из caniuse-db/fulldata-json/data-2.0.json.
  3. Добавить тесты в src/agents.test.js.
  4. Отправить pull request, упомянув в описании @ai @ben-eb.
  5. Форкнуть browserslist.
  6. Добавить в QUERIES новый запрос.
  7. Добавить тесты на новый запрос.
  8. Написать в документации о новом запросе.
  9. Отправить pull request.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Алексей Комаров Алексей КомаровАлексей Комаров

Фронт: Улучшить поддержку Grid Layout от IE в Autoprefixer

Для новичков, задача на неделю

Autoprefixer умеет вставлять -ms- префиксы для CSS Grid Layout, заменяя синтаксис, но эта поддержка очень ограничена. Есть мнение, что ее можно улучшить.

Польза: разобраться в Grid Layout, принять участие в большом open-source проекте.

  1. Посмотреть примеры в issue.
  2. Почитать документацию по указанным свойствам Grid Layout.
  3. Сравнить с документацией на свойства IE/Edge.
  4. Форкнуть autoprefixer.
  5. Новые сойства добавить в data/prefixes.js, если их там еще нет.
  6. В lib/hacks создать/добавить логику изменения синтаксиса.
  7. Добавить новые примеры в test/cases/grid.*.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Новиков Андрей НовиковАндрей Новиков

Помог Игнат Закревский Игнат ЗакревскийИгнат Закревский

Бэк: OmniAuth-стратегия для входа через новый eBay OAuth API

Для новичков, задача на неделю

Необходимо разработать OmniAuth-стратегию для входа в приложения на Ruby с учетной записью eBay в виде отдельного гема.

Сейчас есть гемы, которые реализуют вход через метод Auth’n’auth (например, подзаброшенный гем omniauth-ebay), а через метод OAuth — нет. (Технически оба метода работают по протоколу OAuth, что вносит путаницу).

Для работы с новыми REST API eBay пользователь должен входить именно через новый метод входа.

Польза: возможность разобраться, как же работает вход через соцсети протокол OAuth и библиотека OmniAuth.

Решение: итоговая реализация основана на решении Игната Закревского, но и Андрей Падерин и Илья Долгирев прислали рабочие решения, за что им выражается благодарность.

Что нужно реализовать:

Ruby gem с OmniAuth-стратегией и тестами на взаимодействие с eBay.

Советы по реализации

Язык реализации: Ruby.

Документация начинается здесь и продолжается здесь.

Примечание: После успешной аутентификации пользователя на стороне eBay, у нас нет никакой информации, кто же к нам пришел. Для этих целей провайдеры обычно предоставляют так называемый UserInfo endpoint, но проблема в том, что в новых eBay REST API такого нет. Поэтому для получения информации необходимо делать запрос к методу getUser старого Trading API с указанием нового токена заголовке X-EBAY-API-IAF-TOKEN (мы пишем это здесь, потому что в документации этого не найти).

Инструкции по выполнению

  1. Форкнуть проект omniauth-ebay-oauth
  2. Реализовать необходимую функциональность.
  3. Создать pull request.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Вова Дем Вова ДемВова Дем

Помог Николай Сверчков Николай СверчковНиколай Сверчков

Бэк: Clowne: инструмент для клонирования моделей

Для продвинутых, задача на неделю

Необходимо написать инструмент для клонирования моделей (например, Active Record) с гибкими настройками. Существующие гемы (deep_clonable и amoeba), к сожалению, неудобны при работе со сложной бизнес-логикой и завязаны на ActiveRecord.

Польза: попрактиковаться в написании расширяемого DSL на Ruby и написать инструмент, которым будет активно пользоваться сообщество.

Что должен уметь Clowne?

  • Конфигурация логики клонирования на уровне модели через DSL c поддержкой наследования
class PostCloner < Clowne::Cloner
  # клонировать все ассоциированные объекты
  include_all
  
  # клонировать указанную ассоциацию
  include_association :comments
  
  # указать scope для ассоциации
  include_association :comments, -> { where('created_at > ?', 1.year.ago) }
  # или именнованный scope
  include_association :comments, :this_year
  
  # исключить ассоциацию (если она была добавлена через include_all или в родительском конфиге)
  exclude_association :likes
  
  # обнулить поля
  nullify :external_id, :modified_at, :modified_by
  
  # пользовательский блок, вызываемый в конце клонирования
  finalize do |source, record|
     # ...
  end
end

Для клонирования объекта вызываем:

cloned_post = PostCloner.call(post)
  • Поддержка контекста
# Дополнительно указываем контекст и произвольные параметры
cloned_post = PostCloner.call(post, for: :another_user, user_id: 123)

class PostCloner < Clowne::Cloner
  ...
  # в конфигурации описываем именнованный контекст
  context :another_user do
    nullify :user_id
    
    # в модификаторах ассоциаций имеем доступ к доп. параметрам
    include_association :likes, -> (params) { where.not(user_id: params[:user_id]) }
    
    # и в finalize
    finalize do |source, record, params|
      record.user_id = params[:user_id]
    end
  end
end

# Только произвольные параметры
cloned_post = PostCloner.call(post, user_id: 123)
  • Вложенные объекты клонируются с использованием собственных конфигов (но можно указать другой), доп. параметры передаются сверху вниз
# По умолчанию для модели Comment
class CommentCloner < Clowne::Cloner
  ...
end

class SimpleCommentCloner < Clowne::Cloner
  ...
end

class PostCloner < Clowne::Cloner
  include_associations :comments, clone_with: SimpleCommentCloner
end
  • Если для модели не существует конфига, то клонируем только атрибуты, без ассоциаций

  • Механизм клонирования должен подразумевать интеграцию с разными фреймворками (не только Active Record), то есть должен быть внутренний API для написания адаптеров для произвольных фреймворков

  • По умолчанию должна быть только поддержка ActiveRecord:

class Post < ActiveRecord::Base
  # Явно указать класс клонера
  clone_with ArticleCloner
end

post.clone(params) == ArticleCloner.call(post, params)

Инструкции по выполнению

  1. Форкнуть проект clowne на GitHub.
  2. Реализовать необходимый функционал.
  3. Сделать Pull Request.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Вова Дем Вова ДемВова Дем

Помог Юрий Лебедев Юрий ЛебедевЮрий Лебедев

Бэк: Active Record JSONB ассоциации

Для продвинутых, задача на неделю

Необходимо реализовать возможность хранить данные для ассоциаций (внешние ключи) в поле колонки типа JSONB (PostgreSQL), сохранив при этом большую часть функционала ассоциаций Active Record.

Польза: возможность научиться работать с внутренностями ActiveRecord и JSONB.

Часть 1. Все яйца в одну корзину.

Рассмотрим простой пример:

class Profile < ActiveRecord::Base
  # передаём дополнительную опцию `store`,
  # которая указывает, что мы хотим хранить ключ
  # не в отдельной колонке ("user_id"),
  # а в jsonb-колонке "extra".
  belongs_to :user, store: :extra
end

class SocialProfile < ActiveRecord::Base
  belongs_to :user, store: :extra
end

class User < ActiveRecord::Base
  # в обратной связи указываем, что связь через store.
  # Вопрос: можно ли опустить явное указание того,
  # что используется store, и "узанавать" его из связяннoй модели?
  has_one :profile, foreign_store: :extra
  has_many :social_profiles, foreign_store: :extra
end

Этот функционал позволяет хранить информацию о разных ассоциациях в одной JSONB колонке.

Что мы хотим?

  • Поддержка стандартного функционала ассоциаций (опции foreign_key, inverse_of и т.д.)
  • Рабочий preload / includes:
User.all.includes(:profile)
#=> SELECT * FROM users
#=> SELECT * FROM profiles where extra->>'user_id'::int IN (...)
  • Рабочий eager_load / joins.
  • Поддержка создания/удаления подходящих индексов в миграциях:
add_reference :profiles, :users, store: :extra, index: true

Часть 2. Много-Много.

Используя JSONB, мы можем реализовать связь многие-ко-многим без промежуточной таблицы (если, например, количество связей небольшое):

class Label < ActiveRecord::Base
  # в поле extra['user_ids'] мы будем хранить массив id пользователей,
  has_and_belongs_to_many :users, store: :extra
end

class User < ActiveRecord::Base
  # здесь список лейблов в extra['label_ids']
  has_and_belongs_to_many :labels, store: :extra
end

С точки зрения API функционал должен повторять имеющийся для HABTM.

Также было бы неплохо ответить на вопрос – в каких случаях выгоднее использовать такой подход вместо классического?

Лучшим ответом на этот вопрос будет предъявление бенчмарков и их результатов.

Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Вова Дем Вова ДемВова Дем

Помог Руслан Гафуров Руслан ГафуровРуслан Гафуров

Бэк: Поддержка Fabrication в TestProf

Для новичков, задача на неделю

TestProf – это набор инструментов для профилирования тестов, который включает в себя FactoryProf, анализатор использования фабрик в тестах.

Необходимо добавить поддержку Fabrication (альтернатива FactoryGirl) в FactoryProf: сбор общей статистики по использованию фабрик, построение factory flame графиков.

Польза: узнать, как работают профайлеры кода изнутри, познакомиться с гемом Fabrication.

Инструкции по выполнению

  1. Ознакомиться с более подробным описанием задачи или обсудить на GitHub.
  2. Форкнуть проект test-prof на GitHub.
  3. Реализовать необходимый функционал.
  4. Сделать Pull Request.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Вова Дем Вова ДемВова Дем

Помог Илья Долгирев Илья ДолгиревИлья Долгирев

Бэк: Интеграция EventProf и Minitest

Для новичков, задача на неделю

EventProf – один из инструментов, входящих в состав TestProf. На данный момент работает “из коробки” только с фреймворком RSpec.

Необходимо реализовать интеграцию Minitest и EventProf.

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

Инструкции по выполнению

  1. Ознакомиться с более подробным описанием задачи или обсудить на GitHub.
  2. Форкнуть проект test-prof на GitHub.
  3. Реализовать необходимый функционал.
  4. Сделать Pull Request.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Игорь Лобанов Игорь ЛобановИгорь Лобанов

Фронт: Убрать CoreJS из EmojiMart

Для новичков, задача на неделю

EmojiMart — один из лучших контролов для выбора эмодзи. Сейчас у него в зависимостях есть огромный core-js. Эта зависимость нужна для поддержки ES2016+ в IE. Но, судя по всему, они загружают такую большую зависимость ради пары строк кода.

Нужно убрать core-js и починить работу в IE более простыми способами.

Польза: получить опыт оптимизации размера проекта.

  1. Форкнуть emoji-mart.
  2. Создать ветку.
  3. Установить зависимости с помощью yarn install.
  4. Запустить build:example и открыть example/index.html в IE. Убедиться, что всё сейчас работает.
  5. Убрать все импорты core-js из проекта.
  6. Запустить build:example и открыть example/index.html в IE. Найти ошибки.
  7. Переписать проблемные места на ES5. Например, заменив for (item of array) на for (var i = 0; i < array.length; i++).
  8. Если перепистаь на ES5 не получается, импортировать только нужные файлы из core-js.
  9. Если core-js оказался не нужен, с помощью yarn удалить core-js из зависимостей.
  10. Запустить npx size-limit и обновить лимит размера в package.json.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Никита Филатов Никита ФилатовНикита Филатов

Фронт: Уменьшить размер EmojiMart

Для новичков, задача на неделю

EmojiMart — один из лучших контролов для выбора эмодзи. Но сейчас они собирают всё с помощью webpack. В итоге, если пользователь подключает emoji-mart и core-js, у него в сборке оказывается два core-js — один пользовательский и второй от EmojiMart.

Нужно переделать сборку с webpack на просто Babel, сохраняя древовидную структуру. После чего добавить плагин для вырезания propTypes.

Польза: получить опыт оптимизации размера проекта.

  1. Форкнуть emoji-mart.
  2. Создать ветку.
  3. С помощью yarn удалить webpack и webpack-bundle-analyzer из зависимостей.
  4. Переписать задачи build:dist и watch, чтобы они использовали Babel вместо webpack. Можно сразу вызывать babel-cli из package.json или изменить скрипты в scripts/.
  5. Изменить main и size-limit в package.json на использование dist/index.js вместо dist/emoji-mart.js.
  6. Добавить плагин babel-plugin-transform-react-remove-prop-types.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Игорь Дерябин Игорь ДерябинИгорь Дерябин

Фронт: Задержка при состоянии connecting в Logux Status

Для новичков, задача на неделю

Logux Status показывает состояние синхронизации. Функция status() является фундаментом, чтобы построить свой UI состояния синхронизации.

Одни из шагов синхронизации — connecting и connectingAfterWait. Они говорят о том, что Logux пытается подключится к серверу.

Когда нет Wi-Fi, состояния connecting и connectingAfterWait отображаются слишком быстро — всего на 1—10 мс. В итоге интерфейс неприятно мигает.

Польза: принять участие в разработке Logux.

  1. Форкнуть logux-status.
  2. Изучить status.js и как он используется в badge.js.
  3. Изменить код внутри sync.on('state', …), чтобы connecting передавался в callback не сразу, а только если он не изменилася за 100 мс.
  4. Добавить тесты.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Владимир Боровик Владимир БоровикВладимир Боровик

Фронт: Переподключать Logux при появлении связи

Для новичков, задача на неделю

Logux, при разрыве связи, раз в несколько секунд пытается подключиться снова.

Браузеры посылают событие online при появлении связи. Мы можем запускать попытку связи чуть раньше.

Польза: принять участие в разработке Logux; получить опыт работы с редкими API браузера.

  1. Форкнуть logux-sync.
  2. Изучить документацию по API.
  3. Добавить в reconnect.js код, который при событии online пробует подключиться снова.
  4. Добавить тесты.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Игорь Дерябин Игорь ДерябинИгорь Дерябин

Фронт: Опция keepLast для Logux

Для новичков, задача на неделю

Logux хранит события в логе. Чтобы чистить лог, он использует понятие «смысла жизни». У каждого события есть «смысл жизни» — массив строк. В любой момент разработчик может убрать смысл жизни у события. Как только у события не остается смыслов жизни, оно удаляется.

Однако, на практике, часто нужно одно и то же действие — хранить в логе только одно событие какого-то типа. Для этого приходится часто повторять один и тот же код:

log.add(
  { type: 'app/A' },
  { reasons: ['app/lastA'] }
).then(meta => {
  log.removeReason('app/lastA', { maxAdded: meta.added - 1 })
})

Этот код добавляет в лог событие со смыслом жизни app/lastA и удаляет этот смысл у всех предыдущих событий.

Код приходится писать слишком часто. Стоит добавить опцию keepLast, которая бы делала то же самое.

log.add(
  { type: 'app/A' },
  { keepLast: 'app/lastA' }
)

Польза: принять участие в разработке Logux.

  1. Форкнуть logux-core.
  2. Добавить опцию keepLast в Log#add().
  3. Добавить тесты.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Алексей Никифоров Алексей НикифоровАлексей Никифоров

Фронт: Делать несколько попыток при ошибке связи в Yaspeller

Для новичков, задача на неделю

Yaspeller — JS-утилита, которая проверяет орфографию, посылая запрос на сервера Яндекса. Интернет не всегда стабилен — иногда запрос заканчивается ошибкой связи.

Нужно исправить Yaspeller, чтобы он, в случае ошибки, делал еще 2 запроса и только потом возвращал ошибку.

Польза: получить опыт разработки под Node.js.

  1. Форкнуть yandex-speller.
  2. Изучить lib/post.js.
  3. В случае ошибки ETIMEDOUT делать еще 2 попытки.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Константин Мамаев Константин МамаевКонстантин Мамаев

Фронт: Общие тесты для хранилища лога Logux

Для новичков, задача на неделю

Logux может хранить лог в разных хранилищах — в памяти или IndexedDB. На подходе SQL-хранилище.

Сейчас у каждого хранилища свои тесты — много тестов дублируются. Нужно создать общие тесты для всех хранилищ.

Польза: принять участие в разработке Logux; получить опыт тестирования и Promise.

  1. Форкнуть logux-core.
  2. Сгенерировать документацию — yarn run docs.
  3. Изучить API Store из docs/Store.html.
  4. Изучить текущие тесты test/memory-store.test.js.
  5. Форкнуть logux-client.
  6. Изучить текущие тесты test/indexed-store.test.js.
  7. Форкнуть logux-store-tests.
  8. Создать тесты для всего API Store внутри функции eachTest в index.js по примеру теста is a object.
  9. Удалить тест is a object.
  10. Подключить ваш форк logux-store-tests в форк logux-core — в package.json можно указывать версию из GitHub.
  11. Проверить, что MemoryStore проходит новые тесты. Почистить старые тесты от уже ненужных тестов API.
  12. Подключить ваш форк logux-store-tests в форк logux-client.
  13. Проверить, что IndexedStore проходит новые тесты. Почистить старые тесты от уже ненужных тестов API.
  14. Отправить Pull Request всех трех проектов.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Антон Артамонов Антон АртамоновАнтон Артамонов

Фронт: Перенести все логи Logux Server на Bunyan

Для новичков, задача на неделю

Сейчас у Logux Server два типа логов — Human и Bunyan. Но можно сильно упростить код, если генерировать формат Human из Bunyan.

Польза: принять участие в разработке Logux; получить опыт разработки на Node.js и Bunyan.

  1. Форкнуть logux-server.
  2. Изучить, как можно заменять вывод Bunyan на примере bunyan-format.
  3. Запустить ./test/__snapshots__/show.js и посмотреть все варианты вывода сервера.
  4. Изучить формат Human в reporters/human.
  5. Сделать модуль для Bunyan, который брал бы объект текущего bunyan-лога у Logux и выводил его в формате Human. Убедиться, что вывод полностью совпадает с текущим форматом Human.
  6. Покрыть этот модуль тестами.
  7. Переписать reporters/human, чтобы он использовал новый модуль. Проверить, что старые тесты проходят.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Козин Андрей КозинАндрей Козин

Помог Владимир Катюрин Владимир КатюринВладимир Катюрин

Бэк: Привязка параметров запроса к отчету rspec-sqlimit

Для новичков, задача на день

Необходимо доработать сообщение об ошибке RSpec-матчера exceed_query_limit из гема rspec-sqlimit таким образом, чтобы показывать выполненные SQL запросы вместе с их переменными.

Польза: возможность сделать первый вклад в Open Source проект (особенно если вы не знаете, с чего начать). Попутно можно познакомиться с механизмами ActiveSupport Notifications и Instrumentation, разобраться в устройстве матчеров RSpec.

RSpec матчер rspec-sqlimit публикует сообщение об ошибке (превышение лимита SQL запросов) в следующем виде:

require "rspec-sqlimit"

RSpec.describe "N+1 safety" do
  it "doesn't send unnecessary requests to db" do
    expect { User.create(name: "Joe") }.not_to exceed_query_limit(1)
  end
end
Failure/Error: expect { User.create }.not_to exceed_query_limit(0).with(/INSERT/)

  Expected to run maximum 0 queries that match (?-mix:INSERT)
  The following 1 queries were invoked among others (see mark ->):
     1) begin transaction (0.072 ms)
  -> 2) INSERT INTO "users" ("name") VALUES (?) (0.368 ms)
     3) commit transaction (147.559 ms)

В текстах запросов выше знаком (?) отмечены непривязанные параметры.

Эти параметры содержатся под ключом :binds (отдельно от текста запроса) в данных, передаваемом хуком sql.active_record.

Необходимо извлечь параметры запроса из данных и добавить их к сообщению об ошибке, чтобы оно обрело следующий вид:

Failure/Error: expect { User.create }.not_to exceed_query_limit(0).with(/INSERT/)

  Expected to run maximum 0 queries that match (?-mix:INSERT)
  The following 1 queries were invoked among others (see mark ->):
     1) begin transaction (0.072 ms)
  -> 2) INSERT INTO "users" ("name") VALUES ("Joe") (0.368 ms)
     3) commit transaction (147.559 ms)

Это позволит точнее анализировать, что “пошло не так” при прогоне теста, быстрее находить ошибки, вызывающие лишние запросы к базе данных.

Инструкции по выполнению

  1. Форкнуть проект rspec-sqlimit.
  2. Реализовать необходимый функционал.
  3. Сделать Pull Request.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Виктор Пасынок Виктор ПасынокВиктор Пасынок

Фронт: Навигация стрелками на сайте Stylelint

Для новичков, задача на пару дней

У Stylelint есть сайт со списком правил. Они перечисленны списком, но их сложно читать последовательно — нет ссылок на следующее и предыдущее правило.

Польза: получить опыт в JS.

  1. Изучить код сайта и понять, где формируется список правил.
  2. Форкнуть репозиторий с сайтом. Создать ветку.
  3. Добавить на страницу правила ссылку на следующее и предыдущее правило.
  4. Добавить JS-код, который будет слушать нажатия на клавиши и переключать страницы по нажатию на стрелки на клавиатуре.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Вова Дем Вова ДемВова Дем

Бэк: Утилита для запуска WebSocket-клиентов с поддержкой сценариев

Для новичков, задача на неделю

Необходимо разработать Ruby-инструмент (CLI) для выполнения сценариев взаимодействия WebSocket-клиентов с сервером.

Утилита может быть использована как для blackbox-тестирования (в том числе и нагрузочного) WebSocket-приложений, так и просто в качестве удобного консольного клиента при разработке.

Польза: возможность применить на практике методы многопоточного программирования, попрактиковаться в написании CLI, поближе познакомиться с технологией WebSocket.

Решение: итоговая реализация основана на решениях Кирилла Архипова и Сергея Елушева, за что им выражается особая благодарность.

Как это должно работать?

Рассмотрим два примера. Предположим, что наш сервер — это Action Cable.

Пример №1

Предположим, что мы хотим проверить следующий сценарий (echo):

  • клиент отправляет сообщение серверу;

  • сервер в ответ отправляет такое же сообщение клиенту.

Запуск сценария будет производиться так:

$ wsdirector echo.yml ws://localhost:3444/cable

Здесь ws://localhost:3444/echo – путь к нашему WS-приложению, а echo.yml – файл сценария, который может выглядеть так:

# приветственное сообщение от Action Cable
- receive:
    # если поле data – объект, то
    # предполагаем, что это json
    data:
      type: "welcome"
# подписка на канал и ожидание подтверждения
- send:
    data:
      command: "subscribe"
      identifier: "{\"channel\":\"TestChannel\"}"
- receive:
    data:
      type: "subscription_confirmation"
      identifier: "{\"channel\":\"TestChannel\"}"
- send:
    data:
      command: "message"
      identifier: "{\"channel\":\"TestChannel\"}"
      data: "{\"text\": \"echo\",\"action\":\"echo\"}"
- receive:
    data:
      identifier: "{\"channel\":\"TestChannel\"}"
      message: "{\"text\": \"echo\"}"

В случае возникновения ошибки на каком-либо шаге, скрипт должен завершаться с ненулевым статусом (exit code) и выводить в STDERR информацию о том, на каком этапе сценария произошел сбой.

Пример №2

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

  • все клиенты подключаются к серверу и подписываются на канал;

  • клиенты X отправляют сообщение;

  • все клиенты должны получить такое число сообщений, сколько у нас клиентов X.

Кроме того, нам бы хотелось, чтобы мы могли легко конфигурировать число клиентов:

Наша команда будет выглядеть так:

$ wsdirector -s 10 broadcast.yml ws://localhost:3444/cable

А файл сценария broadcast.yml:

# сценарий публикующего клиента
- client:
    # :scale – это параметр переданный в команде через -s
    # multiplier говорит, сколько нам нужно таких клиентов 
    # (коэффициент "размножения")
    multiplier: ":scale"
    actions:
      # приветственное сообщение от Action Cable
      - receive:
          data:
            type: "welcome"
      # подписка на канал и ожидание подтверждения
      - send:
          data:
            command: "subscribe"
            identifier: "{\"channel\":\"TestChannel\"}"
      - receive:
          data:
            type: "subscription_confirmation"
            identifier: "{\"channel\":\"TestChannel\"}"
      # важный момент – ждём, пока все клиенты достигнут этой точки в сценарии
      - wait_all
      # отправляем сообщение в канал
      - send:
          data:
            command: "message"
            identifier: "{\"channel\":\"TestChannel\"}"
            data: "{\"text\": \"hello\", \"action\":\"broadcast\"}"

# сценарий обычного клиента
- client:
    # слушателей мы хотим в 10 раз больше
    multiplier: ":scale * 10"
    actions:
      # аналогичные действия для подписки на канал пропустим (кстати, как бы нам их переиспользовать?)
      ...
      - wait_all
      - receive:
          # каждый клиент должен получить сообщение от каждого публикующего клиента
          multiplier: ":scale"
          data:
            identifier: "{\"channel\":\"TestChannel\"}"
            message: "{\"text\": \"hello\"}"

Советы по реализации

Язык реализации: Ruby.

Код Action Cable каналов из примеров – gist.

Для реализации веб-сокет клиента можно использовать gem websocket-client-simple, а также посмотреть примеры его использования в Rails или Lite Cable.

Инструкции по выполнению

  1. Форкнуть проект wsdirector на GitHub.
  2. Реализовать необходимый функционал.
  3. Сделать Pull Request.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Вова Дем Вова ДемВова Дем

Помог Андрей Новиков Андрей НовиковАндрей Новиков

Бэк: Инструмент для создания частичного, анонимизированного дампа базы данных

Для продвинутых, задача на неделю

Необходимо разработать инструмент (gem) для создания частичного, анонимизированного дампа базы данных Rails (ActiveRecord) приложения.

Это позволит нам использовать на тестовых серверах данные, максимально приближенные к боевым, но при этом не делать полный дамп (который может быть очень большим). Дополнительно в целях безопасности мы также хотим анонимизировать часть данных (персональные данные и т.п.).

Польза: возможность познакомится с внутренностями ActiveRecord, попрактиковаться в написании Ruby gems и написать инструмент, которым будет активно пользоваться сообщество.

Почему ActiveRecord?

Решение подобной задачи в общем случае (на уровне самой БД) потребует от нас ручного описания связей между данными и постоянной актуализации этих связей.

Наличие же ORM решает эту проблему практически полностью (если все необходимые данные смоделированы с помощью этой ORM).

Как это должно работать?

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

EvilSeed.configure do |config|
  # Указываем корневые/начальные объекты – те, которые мы хотим выгрузить, со всеми
  # связанными данными.
  #
  # Первый аргумент – название модели, второй – условия для выборки
  config.root("Forum", id: 42) do |r|
    # мы хотим исключить некоторые ассоциации
    # для этого можем использовать регулярные выражения,
    # по которым будет матчится путь к ассоциации.
    #
    # путь к ассоциации – это строка, составленная из названий ассоциаций, по которым мы пришли,
    # разделенных точкой, где первая часть – это название модели.
    #
    # пример: "forum.users.questions"
    r.exclude(
      [
        # мы не хотим дампить настройки трекинг-пикселей
        /\btracking_pixels\b/
      ]
    )

    # кроме того, мы можем ограничить количество выгружаемых объектов ассоциации;
    # например, не более 100 элементов для всех
    r.limit_associations_size(100)

    # для конкретной ассоциации по пути
    r.limit_associations_size(10, "forum.questions")

    # данный подход удобен, если структура связей ближе к дереву, тогда
    # мы можем отсекать ветки
    # если же в структуре много циклов, то мы должны будем выйти за пределы лимита,
    # чтобы сохранить согласованность
  end

  # системные модели, например, роли
  config.root("Role") do |r|
    # исключаем все ассоциации
    r.exclude(/.*/)
  end

  # Преобразование атрибутов – это глобальная настройка
  config.customize("User") do |u|
    # ставим всем пользователям одинаковый пароль
    u["encrypted_password"] = encrypt("qwerty")
  end

  # Анонимизация – это синтаксический сахар для преобразования,
  # который может использовать, например, Faker для генерации данных
  config.anonymize("User")
    name { Faker::Name.name }
    email { Faker::Internet.email }
  end
end

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

EvilSeed.dump("path/to/file")

Советы по реализации

Язык реализации: Ruby.

Инструкции по выполнению

  1. Форкнуть проект evil-seed на GitHub.
  2. Реализовать необходимый функционал.
  3. Сделать Pull Request.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Козин Андрей КозинАндрей Козин

Помог Тимур Рамазанов Тимур РамазановТимур Рамазанов

Бэк: Policy Object Pattern

Для новичков, задача на один-два дня

В GitHub-репозитории tram-policy опубликована документация к gem, реализующему базовый класс для контексто-специфичных валидаторов в Ruby. В описании приводится мотивация, примеры интерфейса и поддерживаемых фич; дан список классов и объектов, составляющих публичный интерфейс. Сейчас репозиторий содержит только документацию без какого-либо кода (помимо тривиальных объявлений).

Задача состоит в том, чтобы полностью разработать gem в соответствии с описанием.

Польза: возможность попрактиковаться в написании gem’ов, реализовать один из базовых паттернов разработки средствами чистого Ruby (попутно сняв «ауру магизма» с валидаторов, как мы привыкли к ним в Rails), познакомиться с классической библиотекой I18n, создать простыми средствами один из базовых компонентов для сложных Rails/PORO приложений.

Решение: Второе и третье места с благодарностью за участие в разработке достаются Анастасии Власовой и Сергею Чечаеву, также предложившим свои решения.

Задача должна быть по силам новичку с базовыми знаниями Ruby и фреймворка RSpec.

Обратите внимание на то, что все необходимые зависимости уже объявлены в спецификации (файл .tram-policy.gemspec) и Gemfile gem’а. Не добавляйте новых зависимостей сверх указанных. Поскольку речь идет о публичной библиотеке, код должен быть хорошо покрыт тестами.

Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Евгений Шкодин Евгений ШкодинЕвгений Шкодин

Фронт: Виджет для Logux

Для новичков, задача на неделю

Нужно сверстать виджет статуса синхронизации по макетам Антона Ловчикова.

Польза: принять участие в разработке Logux; получить больше опыта в webpack и создании виджетов.

  1. Скачать макеты.
  2. Изучить макеты Badges.png и Badges usage.svg.
  3. Форкнуть logux-status.
  4. Добавить badge.js с функцией badge. Она должна принимать Client и объект настроек.
  5. Она должна возвращать функцию-отписку, при вызове которой виджет удаляется из DOM.
  6. В настройках можно указывать местоположение виджета (в каком углу экрана), стили (Inline Styles) для разных состояний и текст выводимый в виджете.
  7. В состоянии synchronized виджет не виден.
  8. Если клиент перешёл в состояние disconnected, нужно отобразить «Нет интернета» в виджете.
  9. В состоянии wait — добавить «Ваши данные не сохранены».
  10. В состоянии connecting и sending нужно показывать «Сохраняю ваши данные», но только если предыдущее состояние было wait.
  11. Если мы показывали «Сохраняю ваши данные», то при переходе в synchronized, нужно на пару секунд показать «Ваши данные сохранены».
  12. При ошибках wrong-protocol или wrong-subprotocol нужно показывать «Обновите страницу».
  13. При любой другой ошибке — обычный красный виджет.
  14. В файлах badge/ru.js и badge/en.js нужно указать текст по умолчанию.
  15. Стили по умолчанию нужно указать в badge/default.js. SVG-иконки подключать через require('./icon.svg'). Учесть, что стили на странице могут быть любыми, так что лучше сбросить наследуемые свойства.
  16. Добавить виджет в test/demo. Результат можно посмотреть, запустив yarn run demo.
  17. Добавить модульные тесты на функцию.
  18. Добавить документацию в README.md.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Максим Гатилин Максим ГатилинМаксим Гатилин

Фронт: Генератор настроек Stylelint

Для новичков, задача на пару дней

У CSSComb есть шикарный инструмент для генерации настроек. Он содержит неколько шагов, и на каждом шаге показывает несколько примеров кода. Пользователь выбирает, какой ему больше нравится — и после всех шагов получает готовые настройки для CSSComb.

Надо создать такой же для Stylelint. Только показывать настройки прямо в процессе.

Польза: получить реальный сайт в резюме, получить опыт в JS.

  1. Изучите Stylelint и выберите пару самых простых настроек.
  2. Создайте новый репозиторий.
  3. Выберите любой сборщик, JS-фреймворк. Например, webpack и React или Vue.js.
  4. Сделайте одностраничный сайт. Справа вопрос — слева файл настроек. Когда пользователь отвечает на вопрос, в настроки добавляется выбранное правило.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Антон Артамонов Антон АртамоновАнтон Артамонов

Фронт: Bunyan-формат в Logux Server

Для новичков, задача на пару дней

Bunyan становится форматом логов де-факто в Node.js. Для удобной интеграции с инфраструктурой в Logux Server нужно добавить поддержку этого формата.

Польза: принять участие в разработке Logux; получить больше опыта в JS и построении систем логирования.

  1. Форкнуть logux-server.
  2. Добавить опцию для смены формата лога.
  3. Скопировать reporters/human в reporters/bunyan — заменить код, сохранив API. Общий код можно вынести в reporters/common.js.
  4. В server.js загружать разные файлы reporters в зависимости от опции.
  5. Покрыть тестами каждый репортер и то, что сервер слушается опции.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помогла Жулдуз Жанкенова Жулдуз ЖанкеноваЖулдуз Жанкенова

Фронт: Тесты для Browserslist CLI

Для новичков, задача на пару дней

Browserslist используют Автопрефиксер, ESLint и Babel. У него есть консольный интерфейс. Но он не покрыт тестами — регулярно в нем находят проблемы.

Польза: получить больше опыта в тестировании.

  1. Форкнуть Browserslist.
  2. Придумать, как тестировать ./cli.js. Например, можно его вызывать с помощью spawn().
  3. Покрыть тестами.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Алексей Кузнецов Алексей КузнецовАлексей Кузнецов

Фронт: Страница тестирования Logux Status

Для новичков, задача на пару дней

Для UI-функций недостаточно модульного тестирования. В Logux Status нужна страница, где можно было бы в реальности посмотреть на все его возможности.

Польза: принять участие в разработке Logux; получить больше опыта в JS и webpack.

  1. Форкнуть logux-status.
  2. Сделать скрипт запуска dev-сервера webpack с одной HTML-страницей.
  3. Для нее написать JS-файл, который брал бы Logux Client и подключал бы его к ServerSync через LocalPair.
  4. Подключить к клиенту все функции Logux Status.
  5. На страницу добавить чекбокс «Connected».
  6. На страницу добавить кнопки «Error after 3 seconds» и «Send server error after 3 seconds».
  7. На страницу добавить кнопку «Add action to log». Сразу ставить действиям reasons: ['test'] в метадату.
  8. На страницу добавить кнопку «Clean actions».
  9. Сделать, чтобы JS вставлялся внутрь HTML так, чтобы все было в одном файле.
  10. Мы потом выложим эту страницу на GitHub Pages. Так что на ней нужно написать коротко о Logux и о том, что страница тестирует все функции Logux Status. И не забыть поместить логотип Logux, чтобы было красиво.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Роман Фурсов Роман ФурсовРоман Фурсов

Фронт: Цвета в логере Logux

Для новичков, задача на пару дней

В Logux Status есть log(), который выводит в консоль информацию о том, что происходит с Logux. Вывод идет обычным текстом, хотя Chrome уже поддерживает цветной вывод.

Польза: принять участие в разработке Logux; получить больше опыта в JS и console.

  1. Форкнуть logux-status.
  2. Сделать у всех текстов в log.js префикс Logux:.
  3. Найти надежный способ определения того, поддерживает ли браузер цветной вывод.
  4. Подсветить префикс Logux: фирменным желтым фоном с логотипа Logux.
  5. Подсветить жирным node ID, имя состояния и тип action в сообщениях.
  6. Добавить во второй аргумент опцию отключения подсветки.
  7. Добавить тесты к опции и определению подсветки.
  8. Добавить абзац про подсветку в документацию.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Владимир Трухин Владимир ТрухинВладимир Трухин

Фронт: Отображать ошибки с Logux-сервера на клиенте

Для новичков, задача на пару дней

Logux-сервер работает с клиентом по веб-сокету. При ошибке сервера, клиент не отобразит страницу с ошибкой, как было бы с PHP или Ruby on Rails.

Поэтому надо добавить способ отображения серверной ошибки к консоли браузера.

Польза: внести свой вклад в протокол Logux; получить больше опыта в JS.

  1. Форкнуть logux-protocol.
  2. Добавить в описание протокола команду ["debug", string type, any data].
  3. Форкнуть logux-sync.
  4. Добавить в BaseSync метод sendDebug() для отправки команды и событие debug при получении команды.
  5. Добавить тесты для новых возможностей.
  6. Форкнуть logux-server.
  7. Добавить в BaseServer метод debugError(error), который отправит всем клиентам команду debug с типом error и stacktrace.
  8. Добавить в Server автоматический вызов debugError при ошибке, если this.env равен development.
  9. Добавить тесты на новую логику сервера.
  10. Форкнуть logux-client.
  11. При получении события debug с ошибкой, выводить ее в консоль, помечая, что это ошибка сервера. Желательно, чтобы ошибка показывалась как обычная JS-ошибка со стандартным UI для stacktrace.
  12. Добавить тесты на вывод ошибки.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Роман Фурсов Роман ФурсовРоман Фурсов

Фронт: Добавить ES2015+ в конфиг ESLint для Logux

Для новичков, задача на пару дней

Logux написан на ES5, чтобы работать в браузере без компиляции. Но Logux Server не будет работать в браузере. Минимальной версией node.js будет 4, так что его можно переписать на ES6.

Польза: принять участие в разработке Logux; получить больше опыта в работе с ESLint и ES6.

  1. Форкнуть eslint-config-logux.
  2. Создать файл node4.js, где подключить node/no-deprecated-api и node/no-unsupported-features (для node.js 4) из eslint-plugin-node.
  3. Добавить в node4.js правила, которые обяжут использовать ES6-функции, достпуные в node.js 4.
  4. Разделить документацию на инструкции для index.js и для node4.js.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Андрей Мануйлов Андрей МануйловАндрей Мануйлов

Фронт: Логер в Logux Status

Для новичков, задача на пару дней

Logux Status — это подборка методов отображения статуса синхронизации в браузере. Нужно добавить вывод процесса синхронизации через console.log.

Польза: принять участие в разработке Logux; получить больше опыта в JS.

  1. Форкнуть logux-status.
  2. Добавить log.js с функцией log. Она должна принимать Sync.
  3. Она должна возвращать функцию-отписку, при вызове которой логгер перестанет работать.
  4. Если был передан не Sync, а объект со свойством sync (например, Logux Client), то брать Sync оттуда.
  5. Написать код подписки на connect, state, error и clientError. По этим событиям выводить в консоль браузера, что происходит с Logux.
  6. Написать код подписки на add у sync.log. Выводить в консоль информацию о новом событии в логе.
  7. Добавить тесты для этой функции.
  8. Добавить ее в index.js и добавить тесты на то, что она там есть.
  9. Добавить документацию в README.md.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Константин Епишев Константин ЕпишевКонстантин Епишев

Фронт: Перевести Logux-сервер на ES6

Для новичков, задача на пару дней

Logux написан на ES5, чтобы работать в браузере без компиляции. Но Logux Server не будет работать в браузере. Минимальной версией node.js будет 4, так что его можно переписать на ES6.

Польза: принять участие в разработке Logux; получить больше опыта в работе с ESLint и ES6.

  1. Форкнуть logux-server.
  2. Сменить настройки ESLint на eslint-config-logux/node4.
  3. Обновить синтаксис везде, где ESLint скажет.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Андрей Мануйлов Андрей МануйловАндрей Мануйлов

Фронт: Привлекать внимание при ошибке в Logux Status

Для новичков, задача на пару дней

Logux Status — это подборка методов отображения статуса синхронизации в браузере. Нужно добавить смену <title> при ошибке, чтобы подсветить вкладку в браузере.

Польза: принять участие в разработке Logux; получить больше опыта в JS.

  1. Форкнуть logux-status.
  2. Добавить attention.js с функцией attention. Она должна принимать Sync.
  3. Она должна возвращать функцию-отписку, при вызове которой смена <title> перестанет работать.
  4. Если был передан не Sync, а объект со свойством sync (например, Logux Client), то брать Sync отткуда.
  5. Написать код подписки на событие error и при любом событии, кроме timeout, добавлять к <title> * и убирать ее при открытии вкладки (через Page Visibility API).
  6. Добавить тесты для этой функции.
  7. Добавить её в index.js и добавить тесты на то, что она там есть.
  8. Добавить документацию в README.md.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Андрей Мануйлов Андрей МануйловАндрей Мануйлов

Фронт: Смена favicon в Logux Status

Для новичков, задача на пару дней

Logux Status — это подборка методов отображения статуса синхронизации в браузере. Нужно добавить смену favicon при онлайне, офлайне и ошибке.

Польза: принять участие в разработке Logux; получить больше опыта в JS.

  1. Форкнуть logux-status.
  2. Добавить favicon.js с функцией favicon. Она должна принимать Sync и набор ссылок на favicon для обычного состояния, офлайна и ошибки.
  3. Она должна возвращать функцию-отписку, при вызове которой смена favicon перестает работать.
  4. Если был передан не Sync, а объект со свойством sync (например, Logux Client), то брать Sync отткуда.
  5. Написать код подписки на событие state и смену обычный/офлайн favicon.
  6. Написать код подписки на событие error и при любом событии, кроме timeout, сменять иконку на иконку ошибки.
  7. Добавить тесты для этой функции.
  8. Добавить её в index.js и добавить тесты на то, что она там есть.
  9. Добавить документацию в README.md.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Владимир Трухин Владимир ТрухинВладимир Трухин

Фронт: Подтверждения закрытия вкладки в Logux Status

Для новичков, задача на пару дней

Logux Status — это подборка методов отображения статуса синхронизации в браузере. Нужно добавить подтверждение закрытия вкладки при неотправленных событиях в логе.

Польза: принять участие в разработке Logux; получить больше опыта в JS.

  1. Форкнуть logux-status.
  2. Добавить confirm.js с функцией confirm. Она должна принимать Sync и текст предупреждения (с текстом по умолчанию).
  3. Она должна возвращать функцию-отписку, по вызове которой предупреждение перестает работать.
  4. Если был передан не Sync, а объект со свойством sync (например, Logux Client), нужно брать Sync отткуда.
  5. Написать код подписки на событие state, чтобы при наличии неотправленных событий в onbeforeunload предупреждать пользователя, что не все данные успели синхронизироваться.
  6. Добавить тесты для этой функции.
  7. Добавить ее в index.js и добавить тесты на то, что она там есть.
  8. Добавить документацию в README.md.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Антон Савоськин Антон СавоськинАнтон Савоськин

Фронт: Перевести Logux-сервер на µWS

Для новичков, задача на пару дней

Logux-сервер сейчас использует пакет ws для работы с веб-сокетами. Но пакет uWebSockets гораздо быстрее.

Польза: принять участие в разработке Logux; получить больше опыта в работе с веб-сокетами.

  1. Форкнуть logux-server.
  2. Заменить в проекте ws на uws.
  3. Проверить все тесты и починить проблемы.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Вова Дем Вова ДемВова Дем

Помог Тимур Рамазанов Тимур РамазановТимур Рамазанов

Бэк: Поддержка ассоциаций в Logidze

Для уверенных в себе, задача на неделю

Библиотека Logidze позволяет работать с версиями объектов ActiveRecord моделей и историей их изменений.

Необходимо расширить эту интеграцию, добавив поддержку ассоциаций.

Польза: возможность познакомится с внутренностями ActiveRecord и научиться с ними работать.

Примеры работы, или что делать?

Предположим, что у нас есть две модели:

class Post < ActiveRecord::Base
  has_many :comments
  has_logidze
end

class Comment < ActiveRecord::Base
  belongs_to :post
  has_logidze
end

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

# 2017-01-19
post = Post.create!(post_params)

# 2017-01-22
comment = post.comments.create(body: 'My comment')

# 2017-01-24
comment.update!(body: 'New text')

# смотрим пост до обновления комментария (первый случай)
old_post = post.at('2017-01-23')

# сам пост в этот момент не менялся, но у нас есть ассоциация, которая поменялась
old_post.comments.first #=> 'My comment'

# для более старой версии комментариев не было (второй случай)
very_old_post = post.at('2017-01-20')
very_old_post.comments.size #=> 0

Подводные камни и вопросы для обсуждения

1) В первом случае объект old_post – это тот же самый объект post, так как Logidze возвращает сам объект, если не было изменений с указанного времени. Но для корректной загрузки ассоциаций нам необходимо знать о времени.

Можно изменить это поведение и возвращать объект, который знает о запрашиваемом времени; либо оставить это на откуп разработчикам и советовать им использовать touch: true, чтобы в родительской модели всегда были изменения.

2) Сохранение прошлой версии должно сохранять и соответствующие ассоциации, но только при явном указании:

# не сохраняет старые версии ассоциаций
old_post.save!

post.undo!

# сохраняет предыдущие версии ассоциаций
old_post.save!(associations_versions: true)

post.undo!(old_post.save!(associations_versions: true))

Для обновления ассоциаций мы можем использовать встроенный механизм – ActiveRecord::AutosaveAssociation.

Нужно только научиться включать и выключать его (в случае, если была использована опция autosave: true) самостоятельно.

Во втором случае (very_old_post) нужно также учесть и удаление записей.

Идеи реализации

Нам необходимо уметь вклиниваться в процесс загрузки ассоциаций для объекта, добавляя вызов метода at(time) на загруженных объектах (см. ActiveRecord#associtaion и ActiveRecord::Associations::Association#load_target).

При этом нужно учитывать, какие ассоциации имеют версионирование (т.е. has_logidze).

Инструкции по выполнению

  1. Присоединиться к обсуждению задачи на GitHub.
  2. Форкнуть проект logidze.
  3. Реализовать необходимый функционал.
  4. Сделать Pull Request.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Павел Ковалев Павел КовалевПавел Ковалев

Фронт: Перевести Logux-сервер на снимки Jest

Для новичков, задача на пару дней

Logux-сервер сейчас использует свою систему снимков для тестирования. Но у Jest уже есть хорошая система снимков. Нужно перенести тесты на них.

Польза: принять участие в разработке Logux; получить больше опыта в тестировании.

  1. Прочитать про снимки Jest.
  2. Форкнуть logux-server.
  3. Перевести test/server.test.js и test/reporter.test.js на снимки Jest. Файлы test/snapshots/reports.js и test/servers/servers.js можно перенести в тесты — они больше не нужны отдельно.
  4. Сделать команду yarn run snapshots, которая вызовет jest -u, а потом выведет снимки в консоль — с ее помощью будет удобно смотреть, что сервер будет выводить в консоль во время работы.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Григорий Мороз Григорий МорозГригорий Мороз

Фронт: Понятные ошибки в Logux-сервере

Для новичков, задача на пару дней

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

Польза: принять участие в разработке Logux.

  1. Форкнуть logux-server.
  2. Добавить в server.js перехват ошибки при вызове метода listen().
  3. Найти, как определять ошибки вида «порт занят другой программой» и «у вас нет прав использовать порт меньше 1024».
  4. Создать файл error-helper.js, который будет форматировать и выводить подобные ошибки при запуске сервера. Пример можно посмотреть в reporter.js.
  5. Написать понятный текст для каждой ошибки — что произошло и как исправить. Текст должен быть понятен начинающему программисту.
  6. Добавить тесты.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Павел Ковалев Павел КовалевПавел Ковалев

Фронт: Настройки Logux-сервера через аргументы и переменные среды

Для новичков, задача на пару дней

Сейчас порт, хост и пути к TLS-ключам можно задать только в коде сервера. Нужно добавить в Logux-сервер чтение CLI-аргументов и переменных среды.

Польза: принять участие в разработке Logux; разобраться в Logux-сервере.

  1. Форкнуть logux-server.
  2. Добавить метод options = BaseServer#loadOptions(process, defaults). В нем брать настройки из аргументов --port/-p, --host/-h, --key/-k, --cert/-c и переменных среды LOGUX_PORT, LOGUX_HOST, LOGUX_KEY и LOGUX_CERT.
  3. На параметр --help выводить справку по аргументам, переменным среды и завершать работу.
  4. Добавить тесты для этого метода.
  5. Добавить интеграционное тестирование в test/servers/.
  6. Использовать этот метод в app.listen() в примере кода сервера в README.md.
  7. Добавить описание аргументов и переменных среды в README.md.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Денис Раслов Денис РасловДенис Раслов

Фронт: Проверка сообщений в Logux

Для новичков, задача на пару дней

Нужно добавить в Logux Sync код, который будет проверять формат и типы принятых сообщений.

Польза: принять участие в разработке Logux; разобраться с его протоколом.

Общее правило в разработке серверов — данные клиента не должны вызвать ошибку и падение сервера. Но сейчас Logux Sync не проверяет входящие сообщения. Например, что в сообщении ["ping"] отсутствует число.

В итоге, ошибка в реализации клиента или действия злоумышленика способны привести к падению сервера. Проблема отягощается отсутствием проверки типов в JS.

Нужно добавить проверку типов в Logux Sync. Желательно не использовать большие библиотеки, так как Logux Sync используется и на клиенте.

  1. Изучить возможные сообщения в протоколе Logux.
  2. Форкнуть logux-sync.
  3. Добавить код проверки. Возможно, имеет смысл вынести его в отдельный файл. При неправильном сообщение возвращать ошибку wrong-format, как это делается в BaseSync#onMessage.
  4. Добавить тесты.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помогла Наталия Короткова Наталия КоротковаНаталия Короткова

Фронт: Добавить кнопку Gitter на postcss.org

Для новичков, задача на пару дней

PostCSS использует чат Gitter для помощи разработчикам. У сервиса появился скрипт для добавления чата на любой сайт. Надо добавить его на postcss.org.

Польза: получить опыт с React и красивую строку в резюме.

Сайт postcss.org написан на Phenomic, специальном React-фреймворке для статичных сайтов.

Но скрипт Gitter — не компонент React, а обычный скрипт. Главный вопрос — где их совместить.

  1. Нужно форкнуть postcss.org.
  2. Изучить Phenomic и найти место для скрипта Gitter.
  3. Отправить pull request.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Олег Алешкин Олег АлешкинОлег Алешкин

Фронт: Парсер PostCSS для синтаксиса Sass

Для уверенных в себе, задача на месяц

PostCSS имеет сменные синтаксисы. Это особо полезно для Stylelint, чтобы проверять исходники. Сейчас можно работать с Less и SCSS.

Нужно взять dart-sass и сделать на его основе парсер синтаксиса Sass, который использует отступы.

Польза: познакомиться с командой Sass; многие крупные проекты смогут использовать ваш проект для Stylelint.

dart-sass — это официальный парсер Sass, написанный на Dart. Его можно скопилировать в JS, поэтому он уже есть на npm.

Самый надежный способ — взять этот парсер, получить Sass AST и сконвертировать его в PostCSS AST.

  1. Изучить dart-sass в поисках API, чтобы отпарсить строку в AST.
  2. Если такого API нет, то нужно создать задачу в их репозитории и упоминять там @ai. Если стесняетесь языка — напишите Ситнику, он поможет.
  3. Сделать проект postcss-sass и использовать этот API. Пример конвертирования AST можно посмотреть в postcss-csso.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помогла Анна Столяр Анна СтолярАнна Столяр

Фронт: Перенести проверку протокола в клиент Logux

Для новичков, задача на пару дней

Нужно добавить на клиент предупреждение о нешифрованом веб-сокете в продакшене. Убрать эти ограничения на сервере.

Польза: принять участие в разработке Logux и разобраться с его внутренним устройством.

Веб-сокеты практически бессмысленно использовать без шифрования — старые прокси будут резать непонятный им трафик. Использование WebSockets поверх TLS (wss://) решает проблемы со старыми прокси.

Чтобы пользователи потом не жаловались, мы принуждаем их сразу использовать wss:// в продакшене. Но текущая проверка протокола на стороне сервера не очень оправдана — TLS часто реализуется на уровне nginx.

  1. Форкнуть logux-client.
  2. Выводить подробное предупреждение, если адрес сервера использует ws:// вместо wss:// а домен не равен 127.0.0.1, localhost, ip6-localhost, ::1 и не размещен в зоне .dev.
  3. Перед выводом предупреждения проверять, что в браузере есть console.warn.
  4. Добавить тесты, создав mock на console.warn.
  5. Форкнуть logux-server.
  6. Убрать проверку SSL is required in production mode.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Никита Гусаков Никита ГусаковНикита Гусаков

Фронт: ES5-плагин для ESLint

Для новичков, задача на пару дней

Нужно написать eslint-plugin-es5 с правилами для ESLint для проверки того, что в коде не используется ES2016.

Польза: получить опыт расширения ESLint, поучаствовать в проекте Logux.

Logux не использует Babel. Поскольку часть кода будет работать в старых браузерах, при разработке Logux мы используем ES5.

Есть опасность, что по привычке в код попадет какая-то функция из ES2016 — тесты на Node.js пройдут, а после релиза в Сафари все сломается.

  1. Прочитать документацию по разработке плагинов ESLint.
  2. Создать проект eslint-plugin-es5. Например, скопировать структуру eslint-plugin-babel.
  3. Создать правило по запрету const и let (за основу можно взять правило no-var).
  4. Создать правило по запрету стрелочных функций (на основе prefer-arrow-callback).
  5. Добавить тесты на оба правила.
  6. Выложить проект на npm.
  7. Прислать pull request в eslint-config-logux.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Эмиль Кашкевич Эмиль КашкевичЭмиль Кашкевич

Бэк: Поддержка Yarn для npmdc

Для новичков, задача на пару дней

Сейчас gem npmdc проверяет наличие установленных npm-пакетов и соответствие их версий на основе файла package.json.

Нужно добавить поддержку Yarn.

Польза: возможность попрактиковаться в программировании на чистом Ruby и написании gem’ов, помочь полезному проекту, который нужен в каждом современном большом Ruby веб-приложении.

Как это работает сейчас:

  1. Разбираем файл package.json и строим по нему дерево зависимостей с указанием версии.
  2. Разбираем содержимое папки node_modules.
  3. Для каждого пакета проверяем его наличие в папке node_modules и соответствие версии, указанной в package.json.
  4. Генерируем отчет и показываем его по завершению операции и/или в процессе выполнения (в зависимости от выбранного formatter’а).

Что нужно сделать:

  1. Добавить в конфиг опцию для выбора пакетного менеджера (NPM/Yarn).
  2. Если выбран Yarn, использовать yarn check:
    • следует предусмотреть отсутствие установленного Yarn;
    • следует предусмотреть путь к исполнительному файлу Yarn на случай, если пользователь планирует использовать глобально установленную версию;
    • вывод отчета проверки yarn check следует привести в соответствие с текущим форматом.
  3. Отобразить используемый пакетный менеджер в сообщениях об ошибках и подсказках.
  4. Добавить тесты.
  5. Добавить информацию о новом функционале в документацию.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Олег Алешкин Олег АлешкинОлег Алешкин

Фронт: Загрузка статистики для Browserslist

Для новичков, задача на пару дней

Автопрефиксер, Stylelint, babel-preset-env и cssnext используют Browserslist, чтобы пользователь мог разом указывать список браузеров, которые нужно поддерживать в этом проекте.

Browserslist поддерживает указание браузеров по проценту рыночной доли. Можно указывать реальную статистику пользователей сайта, чтобы точнее считать долю.

Нужно добавить поддержку файла browserslist-stats.json для указания статистики сайта.

Польза: сделать функцию, которой будут пользоваться куча веб-разработчиков.

  1. Нужно форкнуть Browserslist.
  2. Найти, где Browserslist ищет и загружает текущий конфиг.
  3. На основе этого кода пытаться также найти файл browserslist-stats.json. Учтите, что он может быть выше или ниже, чем обычный файл browserslist.
  4. Грузить этот файл той же логикой, что сейчас обрабатывает опцию stats.
  5. Если указана опция stats или process.env.BROWSERSLIST_STATS, то искать browserslist-stats.json не нужно.
  6. Добавить тесты.
  7. Рассказать о новой функции в документации.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Степан Кузьмин Степан КузьминСтепан Кузьмин

Фронт: Browserslist и package.json

Для новичков, задача на пару дней

Автопрефиксер, Stylelint, babel-preset-env и cssnext используют Browserslist, чтобы пользователь мог разом указывать список браузеров, которые нужно поддерживать в этом проекте.

Нужно доработать Browserslist, чтобы он смотрел не только в browserslist, но и в ключ browserslist в package.json.

Польза: сделать функцию, которой будут пользоваться многие веб-разработчики. Эта функция будет использоваться в create-react-app Дэна Абрамова.

Формат package.json ожидается примерно такой:

{
"name": "my-app",
"private": true,
"dependencies": { },
"browserslist": [
 "last 1 version",
 "ie 10"
]
}
  1. Нужно форкнуть Browserslist.
  2. Найти, где Browserslist ищет и загружает текущий конфиг.
  3. Добавить туда поиск и проверку package.json. Этот файл должен также рекурсивно искаться во всех родительских папках.
  4. Если в одной и той же папке находится package.json с нужным ключем и browserslist — выкидывать ошибку, так как ситуация потенциально опасная.
  5. Добавить тесты на обычный случай и на случай с конфликтом конфигов. Конфиги для тестирования можно разместить в папке test/fixtures.
  6. Рассказать о новой функции в документации.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Максим Семенов Максим СеменовМаксим Семенов

Фронт: Среды в Browserslist

Для новичков, задача на пару дней

Автопрефиксер, Stylelint, babel-preset-env и cssnext используют Browserslist, чтобы пользователь мог разом указывать список браузеров, которые нужно поддерживать в этом проекте.

Нужно доработать Browserslist, чтобы в browserslist можно было указывать отдельный список для production и development среды.

Польза: сделать функцию, которой будут пользоваться многие веб-разработчики. Эта функция будет использоваться в create-react-app Дэна Абрамова.

Формат browserslist станет примерно такой:

[development]
last 1 version

[production]
last 2 versions
> 1 %
  1. Нужно форкнуть Browserslist.
  2. Добавить опцию env в API Browserslist.
  3. По умолчанию, ставить env в значение process.env.BROWSERSLIST_ENV, process.env.NODE_ENV или "development".
  4. Исправить парсер конфига, чтобы он поддерживал главы вида [name].
  5. Если глава не указана, парсить как "defaults".
  6. Выбирать список браузеров из конфига в соответствии с env. Если главы, указанной в env, нет, то брать "defaults".
  7. Добавить тесты для всех описанных выше случаев.
  8. Рассказать о новой функции в документации.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Вова Дем Вова ДемВова Дем

Помог Тимур Рамазанов Тимур РамазановТимур Рамазанов

Бэк: Фильтрация полей для версионирования в Logidze

Для новичков, задача на неделю

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

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

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

Как это должно работать?

Есть два противоположных подхода к фильтрации данных: белый список и черный список.

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

$ rails generate logidze:model Post --only="title,user_id,tags"

Во втором — поля, которые мы хотим исключить из версионирования:

$ rails generate logidze:model Post --except="created_at,updated_at"

Инструкции по выполнению

  1. Ознакомиться с более подробным описанием задачи на GitHub.
  2. Форкнуть проект logidze.
  3. Реализовать необходимый функционал.
  4. Сделать Pull Request.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Макс Ларионов Макс ЛарионовМакс Ларионов

Фронт: SugarSS в Sublime Text

Для новичков, задача на пару дней

Нужно добавить поддержку синтаксиса SugarSS в плагин PostCSS для Sublime Text.

Польза: очень простая задача, чтобы разобраться в опенсорсе; позволит понять, как устроен Sublime Text внутри; попасть в анонсы PostCSS.

  1. Посмотреть, как в плагине уже сделали поддержку PostCSS из синтакса SCSS.
  2. Скопировать файл синтаксиса Sass и модифицировать его для SugarSS.
  3. Сделать Pull Request.
  4. Написать Ситнику свой ник в Твиттере и ВК (если есть) для анонса.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Бэк: Добавить новые источники данных в Ossert: StackOverflow

Для уверенных в себе, задача на несколько дней

Нужно добавить в Ossert новые источники данных. Отличным кандидадатом с достаточно богатым API является StackOverflow.

Это позволит охватить еще один важный аспект развития Open-Source библиотек — доступность и объем поддержки, а также заинтересованность в них.

Польза: возможность научиться работать с API StackOverflow и узнать больше о метриках и способах измерения зрелости свободного ПО.

Как это должно работать?

На данный момент сбор информации уже работает для Rubygems, Github и Bestgems. Необходимо совместимым образом организовать сбор с новых источников.

Советы по реализации

За основу предлагается взять любой из существующих классов для сбора в Ossert. Например, Ossert::Fetch::Rubygems, и реализовать класс, осуществляющий сбор интересной информации:

module Ossert
  module Fetch
    class StackOverflow
      def initialize(project)
        ...
      end

      def process
        # Метод сбора основных метрик по проекту
      end
    end
  end
end

Для начала, вам потребуется вникнуть в проблему, решаемую проектом — оценку зрелости свободного ПО.

Для этого нужно проанализировать возможность API вашего источника данных и выбрать:

  1. параметры для сбора;
  2. полезные метрики, которые можно измерить на их основании.

Например:

  • «сколько было вопросов по проекту на StackOverflow»;
  • «какой процент отвеченных вопросов на StackOverflow».

А затем, конечно, организовать сбор этих метрик и параметров.

Инструкции по выполнению

  1. Форкнуть проект Ossert на Github.
  2. Реализовать необходимый функционал.
  3. Сделать Pull Request.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Вова Дем Вова ДемВова Дем

Помог Кирилл Садовник Кирилл СадовникКирилл Садовник

Бэк: Инструмент для тестирования совместимости для AnyCable

Для новичков, задача на неделю

Нужно написать скрипт (и упаковать его в гем), который позволит проводить аттестационное тестирование (от англ. “conformance testing”) приложений-серверов для AnyCable.

Это повысит скорость и удобство разработки новых реализаций серверов, а также поможет поддерживать актуальность текущих реализаций.

Польза: возможность подробно изучить ActionCable и AnyCable, попрактиковаться в написании гемов и написать инструмент, которым будет активно пользоваться сообщество.

Как это должно работать?

Предполагается простой и удобный интерфейс:

$ anycablebility http://localhost:3244/cable

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

Советы по реализации

Язык реализации: Ruby.

В качестве начальных сценариев для тестирования можно взять приемочные тесты для демо-приложения.

В качестве DSL для написания сценариев и их запуска рекомендуется использовать RSpec.

Для непосредественного взаимодействия с сервером через веб-сокеты можно воспользоваться гемом action_cable_client.

Инструкции по выполнению

  1. Форкнуть проект anycablebility на Гитхабе.
  2. Реализовать необходимый функционал.
  3. Сделать Pull Request.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Сергей Долганов Сергей ДолгановСергей Долганов

Помог Сергей Максимов Сергей МаксимовСергей Максимов

Бэк: API Endpoint Sampler

Для уверенных в себе, задача на неделю

Пусть существует Rails приложение с некоторым HTTP API. Будем каждый URL этого API считать эндпоинтом, например:

GET /api/v1/projects/:project_id/notes
GET /api/v1/projects/:project_id/notes/:note_id
POST /api/v2/projects
PUT /api/v3/projects/:project_id

Что хочется получить:

Gem для сбора, просмотра и тэгирования проб (пар запрос/ответ) определенных эндпоинтов HTTP API произвольного Rails-приложения. Тэгом считать произвольную строку.

Что нужно реализовать:

Gem, умеющий следующее:

  • Собирать пробы (пары запрос/ответ) с заданных эндпоинтов, сохранять их в соответствии с правилами:
    • Пробой считать кортеж из:
      • даты-времени;
      • URL запроса;
      • HTTP метода;
      • параметров запроса;
      • тела запроса;
      • тела ответа;
      • набора тэгов.
    • Лимитировать сбор проб: не более Y проб за время X;
    • Автоматически очищать устаревшие пробы по мере получения свежих;
    • Оказывать минимальное влияние на скорость выполнения самого запроса Rails приложением;
    • Хранение организовать на PostgreSQL.
  • Задавать базовую конфигурацию:
    • Ограничение на список эндпоинтов в целом (например, через regexp);
    • Черный список эндпоинтов;
    • Сколько запросов хранить по каждому эндпоинту;
    • Как долго хранить пробу;
    • Сохранять за время X не более Y проб.
  • Конфигурировать обработчики для назначения тегов в момент сбора (например, через lambda функции):

    Sampler.configure do |config|
      config.tag_with "slow", ->(request) { request.time > 200 }
    end
    
  • Просматривать сохраненные пробы, с возможностями:
    • Получения списка доступных эндпоинтов приложения (ограниченных в соответствии с конфигурацией) с количеством имеющихся по ним проб;
    • Получения сводной таблицы проб по эндпоинту с фильтрацией по тэгам (одному или нескольким) (id, timestamp, params, тэги, ссылки на просмотр тела запроса и ответа);
    • Удаления одной или нескольких проб;
    • Просмотра тел запроса и ответа пробы;
  • Устанавливаться в произвольное Rails приложение. Сделать можно, например, так:

    rails generate api:sampler:install
    
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.

Помощь запрашивал Андрей Ситник Андрей СитникАндрей Ситник

Помог Евгений Жаров Евгений ЖаровЕвгений Жаров

Фронт: Тестирование CSS-минификаторов

Для новичков, задача на неделю

Нужно сделать скрипт, который будет брать пару популярных сайтов (типа GitHub) и на их верстке тестировать все минификаторы с помощью gemini или подобного тестирования по скриншотам. Результатом работы будет HTML страница с результатами каждого минификатора.

Польза: разобраться в тестировании по снимкам; познакомиться со всеми разработчиками CSS-минификаторов; строчка в резюме о том, что на качество всех CSS-минификаторов повлияли лично вы.

В качестве примера можно посмотреть на css-minification-benchmark.

  1. Нужно создать GitHub-проект.
  2. Загрузить через npm самые популярные CSS-минификаторы (можно взять все, что использует css-minification-benchmark).
  3. Подобрать известные сайты для тестирования. Нужно взять как хорошие проекты (вроде сайта Github), так и написанные грязно. Еще желательно взять какой-то проект со стилями в опенсорсе.
  4. Написать скрипт, который загрузит свежие стили и HTML этих сайтов.
  5. Написать скрипт, который который прогонит стили через все минификаторы.
  6. Написать скрипт, который запустит тестирование по скриншотами.
  7. Написать скрипт, который сгенерирует HTML-страницу с результатами для каждого минификатора.
Знаете, как решить эту задачу лучше или элегантнее? Оставьте ссылку на свое решение в комментариях.