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

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

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

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

Фронт: Виджет для 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.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Фронт: Перевести 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.

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

Фронт: Парсер 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.

Помощь запрашивает Эмиль Кашкевич Эмиль КашкевичЭмиль Кашкевич

Фронт: Поддержка Yarn для npmdc

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

Сейчас гем npmdc проверяет наличие установленных npm-пакетов и соответствие их версий на основе файла package.json.

Нужно добавить поддержку Yarn.

Как это работает сейчас:

  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. Добавить информацию о новом функционале в документацию.

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

Бэк: Rails Multibase support

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

Нужно создать gem, который умеет переопределять настройки Rails для поддержки приложений, работающих одновременно с несколькими базами данных.

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

Хорошее введение в проблему и способы её решения есть в недавнем (июнь 2016) посте Roberto Ostinelli, а также более ранних публикациях Hunter Madison (январь 2016) и Ken Collins (июнь 2015) — авторах гема secondbase. Этой информации и кода гема вполне достаточно для работы.

Польза от задания, помимо увеличения счастья в мире разработки, еще и в том, что работа с настройками подключений в Rails утратит для Вас привкус магизма. Вы лучше осознаете устройство фреймворка и начнёте ценить изолированные решения вроде Sequel и ROM.

# config/database.yml
---
public_data: # default database
  test:
    adapter: sqlite3
    url:     ./public_data/test.sqlite3
  development:
    adapter: sqlite3
    url:     ./public_data/development.sqlite3
  production:
    adapter: postgresql
    url:     <%= ENV['PUBLIC_DATA_URL'] %>
personal_data:
  test:
    adapter: sqlite3
    url:     ./personal_data/test.sqlite3
  development:
    adapter: sqlite3
    url:     ./personal_data/development.sqlite3
  production:
    adapter: postgresql
    url:     <%= ENV['PERSONAL_DATA_URL'] %>
medical_data:
  test:
    adapter: sqlite3
    url:     ./medical_data/test.sqlite3
  development:
    adapter: sqlite3
    url:     ./medical_data/development.sqlite3
  production:
    adapter: postgresql
    url:     <%= ENV['MEDICAL_DATA_URL'] %>

Основная проблема этих решений в том, что они требуют от разработчика специальных усилий, своего рода шаманизма, в рамках проекта. Гем secondbase частично решает эту проблему, но лишь там, где вы готовы ограничиться двумя (не более) базами данных, и рассматривать одну из них как основную, а другую — как дополнительную. Интерфейсы гема secondbase «заточены» под эту идеологию и будут неудобны, если вы захотите работать с несколькими «равноправными» хранилищами.

Все описанные в статьях механизмы нужно:

  • аккуратно обобщить на случай произвольного количества БД, настраиваемых через единый config/database.yml (с обязательной изоляцией миграций и схем хранилищ друг от друга),
  • реализовать полный набор rake tasks (как классических db:create, так и привязанных к БД db:personal_data:create и многие, многие другие),
  • добавить обязательную поддержку database_cleaner (разумеется, с проверкой того, что этот гем подключен к проекту),
  • реализовать генераторы моделей и миграций Rails, добавив синтаксического сахара: базовых абстрактных классов для database-related моделей и миграций.

С точки зрения пользователя — автора приложения — работа с несколькими базами данных должна быть максимально приближена к идиоматике «монобазового» приложения в стиле: подключи гем — опиши конфигурацию — запусти приложение. It just works™️.

Задание непростое. Потребуется разобраться в кишочках Railtie и инициализации приложения, ActiveRecord (SchemaDumper, Connection), поломать голову над перегрузкой rake tasks и избежанием дублирований. Нужно продумать различные edge cases, возникающих при настройке приложения (например, механизм принудительного разделения миграций разных БД на случай если пользователь прицелится себе в ногу и укажет для двух баз один источник миграций).

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

Фронт: Событийная архитектура 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.

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

Бэк: Инструмент для тестирования совместимости для 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