Статьи

Изгоните своих демонов-новичков, участвуя в упражнениях

Если вы хотите внести код в открытый исходный код, то уровень навыков, который вам нужен, достаточно хорош .

Не «блестящий». Не «свободно» или «опытный». О, конечно, иногда они вам понадобятся. Некоторые проекты, тем не менее, могут использовать вашу помощь, даже если ваш уровень мастерства падает ближе к «едва согласованному», чем «компетентному».

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

Самый очевидный способ сделать это — дать людям практические проблемы.

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

Более 15 000 человек использовали Exercism, как это.

Существует еще один, менее очевидный способ, с помощью которого Exercism помогает людям улучшить свои навыки программирования. Это своего рода мета-игра. Вместо того чтобы писать код и отправлять его в Exercism для обратной связи, вы можете написать код и отправить его в GitHub для обратной связи. Это тот же процесс — обсуждать, обсуждать, учить. В одном случае вы решаете практические проблемы. С другой стороны, вы добавляете практические проблемы, или улучшаете их, или помогаете создавать сам сайт.

Упражнение явно приветствует вклад от людей, которые являются новыми для программирования. Он прилагает усилия для определения проблем, которые могли бы стать хорошим первым патчем. Независимо от того, является ли это вашим первым патчем для проекта или первым патчем с открытым исходным кодом, сопровождающие и участники проекта хотят, чтобы вы добились успеха. Если вы застряли на этом пути, они помогут отцепить вас, чтобы вы могли принять ваш патч. Я должен знать, я создал проект в первую очередь.

Более 650 человек играли в эту мета-игру, внося свой вклад в различные базы кода Exercism.

Сам проект большой и громоздкий; он состоит из более чем 50 хранилищ. У него есть код сайта, код API и код командной строки. У него есть инструменты и сервисы, метаданные и упражнения.

Несмотря на это, в Exercism есть то, чего нет в большинстве проектов: 40+ автономных репозиториев на 40+ разных языках. Один для каждой языковой дорожки.

Ребятам из Haskell не нужно ничего знать о C #. Людям Скала не нужно ничего знать об Эрланге. И вы можете помочь улучшить трек Ruby, зная лишь немного Ruby.

Представляем репозиторий xruby

Репозиторий xruby содержит все упражнения Ruby в Exercism. Это отличное место, чтобы представить свой первый вклад с открытым исходным кодом по нескольким причинам.

Во-первых, упражнения Ruby имеют несколько зависимостей. Если на вашей машине установлен Ruby, то все будет легко настроить.

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

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

Наконец, сопровождающие трассы всегда готовы указать путь или держать руку, если вам это нужно.

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

Есть много способов внести свой вклад в трек Ruby. Эта статья будет посвящена одному из них: переносу упражнения на Ruby.

Перевод существующего упражнения на Ruby

Проще перевести упражнение, чем придумать его.

В Exercism та же проблема обычно реализуется на нескольких языках. Эти языки имеют разные соглашения и разные сильные стороны. В результате их реализации исследуются различные аспекты проблемы. Тем не менее, основная проблема остается неизменной. Как только это было описано и определено, вы можете заимствовать идеи. Вам не нужно беспокоиться о том, чтобы выяснить, какие тесты нужно написать — вы можете сосредоточиться на превращении этих идей в код Ruby.

Портирование упражнения на трассу Ruby сводится к следующим шагам:

  1. Поиск упражнения для перевода.
  2. Помещая упражнение, то есть называя его «чур», чтобы сказать, что вы работаете над ним.
  3. Написание тестового набора и справочного решения.
  4. Настройка упражнения.
  5. Отправка вашей реализации.
  6. Обсуждаем и повторяем.
  7. Отмечают.

Нахождение упражнения для перевода

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

http://x.exercism.io/v3/tracks/ruby/todo

Это сообщает, какие упражнения были определены, но еще не были перенесены на Ruby 1 . В нем перечислены существующие реализации, что упрощает поиск тестовых примеров, которые вы можете написать.

Плохая новость заключается в том, что вы застреваете, разбирая JSON своими глазами. Там нет страницы, которая превращает эти данные в приятную, дружественную страницу HTML.

Сожалею.

Тем не менее, вы можете найти плагин для браузера, который будет форматировать JSON для вас. В противном случае попробуйте jsonlint . Скопируйте и вставьте полезную нагрузку из API в форму. Затем нажмите «проверить JSON», и он будет напечатан как побочный эффект 2 .

Понимание полезной нагрузки JSON

Полезная нагрузка выглядит так:

{ track_id: "ruby", todos: [...] } 

Раздел todos представляет собой массив объектов JSON. Каждая запись содержит информацию об упражнении, которое доступно для перевода. Это означает, что по крайней мере один другой языковой трек реализовал его, а Ruby — нет. Вот запись todo для упражнения Pangram:

 { slug: "pangram", readme: "https://github.com/exercism/x-common/blob/master/pangram.md", data: "https://github.com/exercism/x-common/blob/master/pangram.json", implementations: [...] } 

slug содержит URL-дружественный идентификатор проблемы. Это используется повсеместно: имена каталогов, хеш-ключи, имена файлов.

readme — это URL-адрес описания проблемы, не зависящего от языка. Он написан на GitHub со вкусом Markdown , что позволяет нам превращать его в HTML на веб-сайте, сохраняя его читаемым в виде простого текста. Обратите внимание, что базовое имя файла является проблемным слагом. Как и все другие не зависящие от языка данные о проблемах, README находится в отдельном репозитории, называемом x-common .

Если вам повезет, data будут URL. Если это так, кто-то составил канонический набор тестовых входов и ожиданий. Это делает отличное руководство к проблеме. Если data null вам нужно взглянуть на массив implementations чтобы найти вдохновение.

Каждый элемент в массиве implementations ссылается на одну из существующих реализаций на другом языке. Обратите внимание, что имя каталога для упражнения — это проблема.

Pangram в настоящее время имеет семь реализаций. Выходные данные JSON для отдельной реализации содержат идентификатор языковой дорожки и URL-адрес файлов, определяющих упражнение на этом языке. Как минимум, будет набор тестов и эталонное решение. Иногда вам придется искать в подкаталогах, чтобы найти их.

 { track_id: "elm", url: "https://github.com/exercism/xelm/tree/master/exercises/pangram" } 

Уделите немного времени чтению некоторых README и, возможно, просмотрите некоторые реализации. Найдите упражнение, которое вам нравится.

Выполняя упражнение

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

Найдите проблемный слаг (например, pangram ) в хранилище дорожек Ruby .

В результатах поиска по умолчанию используется «код», а это не то, что вам нужно. В левой части страницы выберите пункт меню «Проблемы». Это будет включать в себя как вопросы, так и запросы извлечения.

экран

Если ничего не происходит, значит, вы готовы идти.

Если есть проблемы или запросы на выгрузку, то вам нужно присмотреться. Кто-то может работать над этим, или работа может быть оставлена. Или проблемы могут быть не связаны. Если сомневаешься, спрашивай!

Также может быть объединенный запрос на pangram (как в случае с pangram ), что, вероятно, означает, что вам нечего делать. Обычно мы разворачиваемся ежедневно, но иногда дела заняты, поэтому для выполнения упражнения может потребоваться день или два, чтобы добраться до сайта. Как только они попадут на сайт, они исчезнут с конечной точки «todo».

Ради этой статьи, допустим, вы решили работать с bracket-push . Вам захочется, чтобы никто не начал работать над этим тоже.

Есть два способа выполнить упражнение:

  1. Откройте вопрос.
  2. (предпочтительно) Открыть запрос на выполнение работ.

(Вариант 1) Открытие вопроса для выполнения упражнения

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

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

 Add 'bracket-push' exercise 

В теле вопроса заявите это для себя.

(Вариант 2) Открытие запроса на извлечение в процессе работы

Эта опция делает еще несколько шагов, но большинство из них вам придется делать позже. Сначала разветвите репозиторий xruby, чтобы получить собственную копию. Затем клонируйте свою вилку.

Перейдите к коду, который вы только что клонировали, и создайте новую ветку. Назовите это для упражнения.

 $ git checkout -b bracket-push 

Далее создайте пустой коммит. Обычно git не позволяет вам совершать коммиты, не выполняя фактически работу, но если вы настаиваете:

 $ git commit --allow-empty -m "[WIP] add bracket-push" 

Переместите новую ветку с пустым коммитом на свою ветвь на GitHub:

 $ git push origin bracket-push 

Посетите ваш форк на GitHub и нажмите большую зеленую кнопку с надписью «Сравнить и запрос на извлечение», которая появляется для недавно созданных веток.

Добавьте комментарий в тело формы, чтобы сказать, что вы будете над ним работать, затем нажмите «Создать запрос на извлечение», чтобы отправить форму.

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

Написание тестового набора и справочного решения

Если вы никогда раньше не писали никаких тестов, то это будет хорошее приключение размером с укус. Если вы написали тесты, но никогда не были в Minitest, то вас ждет удовольствие. Минитест маленький, простой и восхитительно простой 3 .

  1. Внутри каталога exercises создайте каталог для новой реализации. Назовите его после проблемного слага (например, bracket-push ).
  2. Создайте пустой тестовый файл и назовите его слагом с подчеркиванием вместо дефисов (например, bracket_push_test.rb ).
 gem 'minitest', '>= 5.0.0' require 'minitest/autorun' require_relative 'bracket_push' class BracketPushTest < Minitest::Test end 

Первая строка защищает от неподдерживаемых версий Minitest.

Строка autorun — это то, как Minitest заставляет Ruby запускать набор тестов при запуске файла.

Затем мы включаем фактическое решение, которое еще не существует. Имя файла — это проблема, с подчеркиванием вместо дефисов. Обратите внимание, что мы ожидаем, что он будет в том же каталоге, что и тестовый файл. Свободное соглашение в Ruby — иметь отдельные каталоги lib и test , но это было бы излишним.

Наконец, мы определяем сам набор тестов. Обратите внимание, что имя класса начинается с версии проблемного BracketPushTest CamelCase ( BracketPushTest ).

Запустите тестовый набор:

 $ ruby bracket_push_test.rb 

Он будет жаловаться, потому что файл решения отсутствует. Создайте пустой bracket_push.rb и снова запустите тест. Это должно перестать жаловаться.

Внутри класса BracketPushTest вы добавите столько тестов, сколько вам нужно. Вот как выглядит тест:

 def test_count assert_equal 1, Stuff.new.count end 

Обратите внимание на название метода. Начинается с test . Если вы не начнете test , Minitest не узнает, что это тест, и его не запустят. Метод assert_equal — это то, что заставляет тест пройти или не пройти. Он принимает два аргумента: ожидаемое значение и фактическое значение. Ожидаемое значение обычно жестко запрограммировано, а фактическим значением является вызов кода, который вы тестируете.

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

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

Добавляйте по одному тесту за раз. Уточните эталонное решение по ходу дела.

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

Настройка упражнения

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

  1. Добавьте тестовую версию.
  2. Переименуйте файл справочного решения.
  3. Пропустить все, кроме первого теста.
  4. Добавьте упражнение в файл конфигурации дорожки.
  5. Проверьте дорожку.

Добавление тестовой версии

Мы обновляем тесты время от времени. У этого есть прискорбный побочный эффект того, что более ранние решения выглядят недействительными. Они прошли, когда их представили, но рецензенты не могут этого знать. Люди иногда жалуются, что старое решение «не проходит испытания». Правда, но не имеет значения. Они должны просмотреть код, который там.

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

Этот тест должен быть последним, и он будет выглядеть так:

 def test_bookkeeping assert_equal 1, BracketPush::VERSION end 

Добавьте константу VERSION в эталонное решение для соответствия.

Переименование файла справочного решения

Мы используем эталонное решение для тестирования набора тестов — чтобы убедиться, что оно решаемо. Оно не должно доставляться как часть упражнения, когда люди его получают.

Для этого мы используем простое соглашение: API знает, что не нужно доставлять файлы с example в имени.

Переименуйте файл решения в example.rb .

Пропускать все, кроме первого теста

Когда пользователь начинает решать упражнение, у него нет кода. Видеть все неудачи для всех тестов одновременно может быть ошеломляющим и запутанным. Что еще хуже 4 , тесты запускаются в случайном порядке. Это означает, что первый неудачный тест вряд ли будет первым тестом в файле.

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

 def test_bookkeeping skip assert_equal 1, BracketPush::VERSION end 

Люди могут удалить «пропустить» из следующего теста, а затем пропустить его. Вымойте, промойте, повторите.

Обновление конфигурации

Файл config.json в корне хранилища, в конечном счете, решает, что означает «следующий», когда кто-то запрашивает следующее упражнение.

Добавьте кусок упражнения в массив problems . Проблемы упорядочены в зависимости от того, насколько трудно их решить: более простые проблемы находятся в начале списка, более сложные проблемы — ближе к концу. Это не точная наука, и трудно сказать, куда она должна идти. Если у вас нет лучшей идеи, вставьте ее где-нибудь во второй половине.

Проверка трассы

На данный момент есть хороший шанс, что все подключено правильно. Это немного неудобно, поэтому, если это не так, у нас есть сценарии, которые могут помочь.

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

Вы можете скачать его, выполнив следующую команду из корня репозитория xruby:

 $ bin/fetch-configlet 

Вам нужно сделать это только один раз.

Чтобы проверить дорожку, запустите команду bin/configlet . (обратите внимание на точку). Если он говорит «хорошо», ты в порядке.

Затем запустите bundle install , которая установит необходимые зависимости для локальной проверки состояния:

 $ bin/local_status_check 

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

Travis CI выполнит все эти вещи, когда вы отправите запрос на извлечение. Технически вам не нужно их запускать. Просто быстрее ловить вещи, прежде чем их толкают.

Наконец, убедитесь, что вы все зафиксировали, и отправьте это на свою ветку проекта на GitHub.

Отправка вашей реализации

Теперь все должно быть готово к рассмотрению.

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

Первый шаг — убедиться, что история коммитов аккуратна и актуальна. Независимо от того, сколько коммитов вы сделали, это одно изменение. По крайней мере, с точки зрения остальной части проекта. Чтобы очистить все, переберитесь на вышестоящий мастер и раздавите ваши коммиты.

Ознакомьтесь с Руководством по разработке упражнений . Раздел « Основы Git » рассказывает о том, как сделать ребас и сквош. Убедитесь, что в сообщении о фиксации содержится фрагмент проблемы, например, « Выполнить упражнение« толкать скобки »» .

Следующий шаг зависит от того, есть ли у вас открытый вопрос или запрос на извлечение [WIP] .

Если у вас есть открытая проблема, проверьте ветку с вашими изменениями, отправьте ее на GitHub и отправьте запрос на извлечение. Добавьте фразу Closes #XYZ, где XYZ — номер проблемы, которую вы открыли. Это закроет проблему, когда запрос на объединение будет объединен .

Если у вас есть запрос [WIP], вы можете добавить к нему код, отправив больше коммитов в вашу ветку. Если вы измените историю (перебрасывая или сдавив), вам нужно будет использовать флаг --force при нажатии. Это перезапишет вашу ветку с новой историей, обновляя ваш запрос.

 $ git push --force origin bracket-push 

Затем вручную отредактируйте запрос извлечения на сайте, чтобы удалить префикс [WIP] из заголовка.

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

Обсуждать и повторять

Сопровождающие треков Ruby отзывчивы, и вы можете ожидать ответа в течение 24 часов. Если вы ничего не услышите в течение 3 дней, добавьте комментарий в ветку. Это не невежливо — иногда вещи теряются в случайном порядке, и комментирование снова привлекает внимание сопровождающих.

Вы, вероятно, получите некоторые отзывы и указатели. Внесите изменения, зафиксируйте, сдавите и верните --force обратно в вашу ветку.

Продолжайте делать это, пока ваш патч не будет объединен.

Отмечают

Вклад в открытый исходный код — это большое дело.

Это намного больше, чем просто написание нескольких строк кода. Есть инструменты и зависимости. Люди и ожидания. Требуется немного смелости, чтобы погрузиться во все это.

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


[1] На данный момент существует 66 упражнений Ruby, и, согласно http://x.exercism.io/v3/tracks/ruby/todo , можно добавить 38 упражнений.

[2] Вероятно, он окажется «недействительным», потому что ключи в JSON не заключены в двойные кавычки. На самом деле это не проблема, так что вы можете спокойно проигнорировать это.

[3] Если вы не хотите просто прыгать в Minitest без какой-либо подготовки, попробуйте учебник Введение в TDD из Jumpstart Lab, который использует Minitest для объяснения основных концепций разработки через тестирование.

[4] Обычно это хорошая вещь; это гарантирует, что ваши тесты не зависят друг от друга. Вы можете вызвать i_suck_and_my_tests_are_order_dependent! метод в верхней части набора тестов, но он запускает их в алфавитном порядке, а не в том порядке, в котором они определены, поэтому он не будет работать для имитации TDD.