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

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

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

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

Бэк: Гемизация «простейших контрактов» на 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. Покрыть новую функциональность тестами.

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

— Можно мне взять эту задачу?

Все задачи на этой странице еще не решены. Если задача вам интересна — берите и смело делайте. Спрашивать разрешения и становиться в очередь не нужно. Даже если кто-то сделает задачу быстрее вас, не останавливайтесь — ваше решение может быть лучше. Это Open Source!

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

Фронт: Исправить вложенные медиа-выражения в 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-preset-env

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

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

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

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

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

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

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

Бэк: Добавить новые источники данных в 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.

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

Бэк: Добавить поддержку Plezi/Iodine в LiteCable

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

LiteCable – это альтернативная реализация фреймворка ActionCable из Rails, совместимая с ActionCable-клиентами, но при этом имеющая минимум зависимостей.

Необходимо добавить в LiteCable интеграцию с Plezi (Iodine) “из коробки” (по аналогии с тем, как это сделано для AnyCable).

Польза: познакомиться и научиться работать с новым веб-сервером для Ruby приложений (Iodine); разобраться во внутреннем устройстве real-time фреймворков.

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

Iodine – это новый веб-сервер для Ruby приложений (альтернатива Unicorn/Puma/etc), спроектированный специально для работы с большим количеством одновременных подключений (например, веб-сокетов).

LiteCable реализует бизнес-логику работы с сокетами (“каналы”) и предоставляет API для интеграции с непосредственно сервером (на данный момент “из коробки” доступна интеграция с AnyCable.

Задача состоит в том, чтобы сделать использование Iodine в качестве сервера для LiteCable возможным и максимально простым.

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

Вместо “голого” Iodine можно сделать интеграцию с Plezi – микро-фреймворком для работы с веб-сокетами.

Информацию о внутреннем устройстве подписок можно посмотреть тут.

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

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

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

Фронт: Событийная архитектура PostCSS

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

Нужно придумать новый API для плагинов PostCSS — чтобы они все работали вместе, в одном цикле прохода по AST-дереву.

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

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

Сейчас каждый плагин PostCSS проходит по AST-дереву CSS каждый раз заново. В итоге нельзя делать вложенные функции, и при большом количестве плагинов сильно проседает производительность.

У Babel есть более правильный visitor API: когда плагины подписываются на какие-то типы узлов. А внутри PostCSS запускается один проход по дереву, который в нужных местах дергает подписанные плагины.

Первый этап:

  1. Придумать такой API.
  2. Сделать пару примеров псево-кода: как API будет использоваться в простейших плагинах?
  3. Отправить эти примеры Андрею (Gist или проект на GitHub).

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

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

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

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

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

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

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

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

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

За основу предлагается взять любой из существующих классов для сбора в Ossert. Например, Ossert::Fetch::Rubygems, и реализовать класс, осуществляющий сбор интересной информации:

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

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

Для начала, вам потребуется вникнуть в проблему, решаемую проектом — оценку зрелости свободного ПО.

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

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

Например:

  • «сколько было комментариев к постам о проекте с момента последнего релиза»;
  • «сколько уникальных пользователей комментировали посты о проекте».

А затем, конечно, организовать сбор этих метрик и параметров.

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

  1. Форкнуть проект Ossert на Github.
  2. Реализовать необходимый функционал.
  3. Сделать Pull Request.